Getting started with nuxt content - a simple blog page
Tags: webdev, javascript, beginners, tutorial
Published: 2023-04-09 10:03:41

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](https://content.nuxtjs.org/get-started#add-to-a-project) 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:

- Follow the [Nuxt Prerequisites](https://nuxt.com/docs/getting-started/installation#prerequisites)[](url)
- Download the [VS Code MDC Extension](https://marketplace.visualstudio.com/items?itemName=Nuxt.mdc)

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](https://nuxtjs.org/) 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:

```javascript
// yarn
yarn create nuxt-app simple-nuxt-blog
```

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

![Terminal questions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o7cnptau21exgd93eqa8.png)

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

![project created](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/flw75x1khiu99vqxfavs.png)

Next, `cd` into the project directory:

```javascript
cd simple-nuxt-blog
```

Then install the Nuxt Content module:
```javascript
yarn add @nuxt/content
```
Now open the `nuxt.config.js` file and add a new entry to the modules array.

```javascript
//nuxt.config.js

export default {
  // other config
  modules: [
    '@nuxt/content'
  ]
}
```

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**.

```javascript
npx tailwindcss init
```

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.

```javascript
// tailwind.config.js

module.exports = {
  jit: true
  // other config
}
```

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

```CSS
@tailwind base;
@tailwind components;
@tailwind utilities;
```

Now you can start the dev server:

```javascript
yarn dev
```
✨ Well done! A browser window should automatically open on [http://localhost:3000/](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:**

```javascript
// 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...
``` 

**content/html-elements.md:**

```javascript
// 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
---

we’ll discover the top ten HTML elements you might not have known existed...
```

**content/variables.md:**

```javascript
// 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);
```

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:

```javascript
// 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>
```
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yl8nyspsmaf8kt3f3r0s.png)

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:

```javascript
// 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>
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/701qlduwaismyn4spinm.png)

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:

```javascript
// 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>
```
After updating the code, you should be able to search your blog posts, as shown in the gif below.


![demo-gif](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxmgx1vt4o101st39tyz.gif)
The full project is in this [repo](https://github.com/JohnpaulEze/simple-nuxt-blog). 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!