DEV Community

Cover image for Getting started with nuxt content - a simple blog page
Johnpaul Eze
Johnpaul Eze

Posted on

Getting started with nuxt content - a simple blog page

Building a blog page from scratch can be a daunting task for beginners. However, with the help of Nuxt Content, it can be made easy and fun. In this tutorial, I will show you how to build a stunning blog page using Nuxt content and Tailwind CSS.

What is Nuxt Content?

Nuxt Content is a module for Nuxt.js that provides a simple way to manage content for your application. It allows developers to write their content in Markdown, YAML, or JSON files and then easily import and display it in their application.

Nuxt Content comes with a number of features that make it easy to manage content, including:

  • Markdown, YAML, and JSON support
  • Automatic image optimization
  • Built-in search functionality
  • Support for multiple languages
  • Automatic SEO optimization
  • And more!

Getting Started

Before getting started, please make sure to have installed the recommended setup:

To get started with Nuxt Content, you will need to have a basic understanding of Nuxt.js. If you are new to Nuxt.js, you may want to check out their documentation and complete the tutorials before diving into Nuxt Content.

Project Setup

Let’s start with creating a new Nuxt project. You can do so by running the command below:

// yarn
yarn create nuxt-app simple-nuxt-blog
Enter fullscreen mode Exit fullscreen mode

You will be prompted to answer some questions. You can see how I answered them in the image below:

Terminal questions

After the project is successfully created, the terminal will look like the image below:

project created

Next, cd into the project directory:

cd simple-nuxt-blog
Enter fullscreen mode Exit fullscreen mode

Then install the Nuxt Content module:

yarn add @nuxt/content
Enter fullscreen mode Exit fullscreen mode

Now open the nuxt.config.js file and add a new entry to the modules array.

//nuxt.config.js

export default {
  // other config
  modules: [
    '@nuxt/content'
  ]
}
Enter fullscreen mode Exit fullscreen mode

I will use Tailwind CSS to make things neat and quick. However, If you don’t want to use it, you can skip the setup steps and start the dev server. Otherwise, run the command below to create the Tailwind CSS config.

npx tailwindcss init
Enter fullscreen mode Exit fullscreen mode

The command above will create a new file called tailwind.config.js at the root of your project. Open this file and add jit property as shown below.

// tailwind.config.js

module.exports = {
  jit: true
  // other config
}
Enter fullscreen mode Exit fullscreen mode

Next, create an assets/css/tailwind.css file and add the code below:

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Now you can start the dev server:

yarn dev
Enter fullscreen mode Exit fullscreen mode

✨ Well done! A browser window should automatically open on http://localhost:3000/.

This concludes the setup. Next, let's create a few blog posts. To do this you will need to create a content directory where you will store your content files.

Now, let’s create a few markdown files in our content directory.

content/hello-world.md:

// content/hello-world.md

---
title: "Hello, World!"
description: "building my first ever web page "
date: 2023-03-14
slug: How-to-build-your-first-web-page
---

Building my first ever web page was somewhat challenging but If you can, imagine a time before the invention of the Internet...
Enter fullscreen mode Exit fullscreen mode

content/html-elements.md:

// content/html-elements.md

---
title: Top Hmtl Elements to use more often
description: HTML is a powerful markup language that can...
date: 2023-03-29
slug: Top-html-elements-to-use-more-often
---

well discover the top ten HTML elements you might not have known existed...
Enter fullscreen mode Exit fullscreen mode

content/variables.md:

// content/variables.md

---
title: Getting started with variables and data types
description: variables are important...
date: 2023-04-02
slug: getting-started-with-variables-and-data-types
---

Variables are containers for pieces of data. That data can be one of many different data types.

let firstName = 'John';
let lastName = 'Doe';

// We can do a console.log to show the value
console.log(firstName, lastName);
Enter fullscreen mode Exit fullscreen mode

The Markdown files consist of the front matter and body. The front matter goes between triple dashes (---). It must be written in valid Markdown, YAML, or JSON format. This config will be later injected into a Nuxt Content document. In this example post, we have a title, a description, a date, and a slug. You can, of course, add more properties if you want to. For instance, an image URL or author.

Now that we have successfully set up our blog posts files, it only makes sense to fetch and render the posts on the homepage for readers to see. To do that, head to pages/index.vue file and add the following:

// pages/index.vue

<template>
  <div
   class="max-w-3xl max-w-5xlmin-h-screen
        flex justify-center mx-auto my-12">
        <main class="w-full">
        <h1 class="text-2xl font-semibold mb-6">My blog page</h1>
     <section class="space-y-4 divide-y">
        <article v-for="post of posts" 
        :key="post.slug"class="pt-4">
        <h2 class="text-lg mb-2 text-blue-700 
            hover:text-blue-800">
            <nuxt-link :to="`/blog/${post.slug}`">
              {{ post.title }}
            </nuxt-link>
       </h2>
          <span>
            {{ post.description }}
          </span>
        </article>
      </section>
    </main>
  </div>
</template>

<script>
export default {
  data() {
    return {
      posts: [],
    }
  },
  async fetch() {
    this.posts = await this.$content().fetch()
  },
}
</script>
Enter fullscreen mode Exit fullscreen mode

To fetch articles, Nuxt Content injects the $content instance globally. In order to query the content, it provides a powerful MongoDB-like API. As you can see in the snippet above, we do not provide any filters, so all the posts will be fetched immediately.
The image below shows how the homepage should look like:

homepage

However, If you click on one of the links, it should redirect you to a blog/<slug> page, which doesn’t exist yet, hence let’s create one.

View Dynamic Blog Post Page

To do this Let’s create a pages/blog/_slug.vue file and add the following code to it:

// pages/blog/_slug.vue

<template>
  <div class="max-w-3xl mx-auto min-h-screen my-12">
    <div v-if="post">
     <h1 class="text-2xl font-semibold mb-6">{{ post.title }</h1>
      <nuxt-content :document="post" />
      <div class="mt-8">
        <nuxt-link
          to="/"
          class="active:bg-green-700 bg-green-500 
          rounded text-white font-bold py-3 px-5"
          >Back to blog</nuxt-link>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      post: null
    };
  },
  async fetch() {
    this.post = (
      await this.$content()
        .where({ slug: this.$route.params.slug })
        .limit(1)
        .fetch()
    )?.[0];
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

In the snippet above, you notice that instead of calling the fetch method immediately, we provided a slug filter extracted from the route params. We also limit the results to one, as we want to fetch only the specific blog post. Hence, we don’t expect more results as slugs should be unique. The fetch post is then passed to the <nuxt-content /> component via the document prop.

The image below shows the “Getting started with variables and data types” post:

blog-image

Awesome! we have our blog working. The site displays all blog posts and allows users to read each article.

Next, let’s add a blog search functionality.

Blog Search

To allow users to enter a search query, we need to add an input field. Besides that, we will update the fetch method, so if there is a search query available, we will perform a text search instead of just fetching all the articles. To do this, head back to the pages/index.vue file and update it with the following snippet:

// pages/index.vue

<template>
  <div
    class="max-w-3xl max-w-5xlmin-h-screen flex justify-center 
           mx-auto my-12">
    <main class="w-full">
      <h1 class="text-2xl font-semibold mb-6">My blog page</h1>
      <section>
        <form class="flex flex-col space-y-2 mb-4" 
                     autocomplete="off">
          <label for="search-blogs" class>Search blogs</label>
          <input id="search-blogs" v-model="query"
            class="px-3 py-2 shadow border border-gray-200"
            type="text"/>
        </form>
      </section>
      <section class="space-y-4 divide-y">
        <article v-for="post of posts" :key="post.slug" 
                 class="pt-4">
          <h2 class="text-lg mb-2 text-blue-700 
                     hover:text-blue-800">
            <nuxt-link :to="`/blog/${post.slug}`">
              {{ post.title }}
            </nuxt-link>
          </h2>
          <span>
            {{ post.description }}
          </span>
        </article>
      </section>
    </main>
  </div>
</template>

<script>
export default {
  data() {
    return {
      query: "",
      posts: []
    };
  },
  async fetch() {
    if (!this.query) {
      this.posts = await this.$content().fetch();
      return;
    }
    this.posts = await this.$content()
      .search(this.query)
      .fetch();
  },
  watch: {
    query: "$fetch"
  }
};
</script>
Enter fullscreen mode Exit fullscreen mode

After updating the code, you should be able to search your blog posts, as shown in the gif below.

demo-gif
The full project is in this repo. You can fork it to quickly get started.

Conclusion

In this tutorial, we created our own blog using Nuxt and Nuxt Content, we even went over implementing a blog search functionality. However, you can add more features, such as search debouncing, filtering by categories, and even pagination or lazy loading more articles with infinite scroll. By following the steps outlined in this tutorial, you should now be able to create a beautiful and responsive blog page. So what are you waiting for? Start building your own stunning blog page today!

Top comments (0)