October 10, 2021 | Last updated: December 22, 2021
Creating tags for your Nuxt Blog with Nuxt/Content
Learn how to build a Nuxt blog and filter your posts and projects with tags.
Time: 6min
Introduction
Quite recently I revamped my website using a newer version of Nuxt and decided to use Nuxt Content for my Blog. While creating the main blog and projects pages though, I came across a quite common issue, tags.
You see when you first land in the main Blog page you get a list of blog posts which can be overwhelming, especially since I haven't implemented pagination yet.
A quick alternative for me, was to create tags so you can filter out the results based on the topic you are interested in.
The how
In my current configuration I do have one main component for the Blog that is responsible to list all the blogs found in the content folder.
<!-- BlogList.vue -->
<template>
<!-- the list of blogs -->
<ul class="...">
<!-- the item/post wrapper -->
<li
v-for="blog of blogs"
:key="blog.slug"
...
>
<NuxtLink :to="`/blog/${blog.slug}/`">
<img />
<span class="sr-only">Link to the blog post</span>
</NuxtLink>
<div class="flex items-center px-4 pt-3 mb-2">
...
<div class="flex items-center">
<div v-for="(tag, idx) of blog.tags" :key="idx">
<!-- The Tag component -->
<UITag :tag="tag"></UITag>
</div>
</div>
</div>
...
</div>
</li>
</ul>
</template>
This component has a ul
which holds the wrapper element of the blog post. Then I loop through the blog object and display the list items, aka blog post. Just after the date I am printing the tag
which is another component. This tag component accepts a string as a prop named, well, tag
and it's the slug of the tag. Lets take a look inside the component itself to see how this all works.
<!-- Tag.vue -->
<template>
<NuxtLink class="..." :to="`/blog/tags/${tag}/`">
<IconTag class="text-kt-ice-white dark:text-text-kt-dark inline" />
{{ tag }}
</NuxtLink>
</template>
This component is a link, which will navigate the user into the special route /blog/tags/#tag
. The last part is the actual prop we previously passed in the component.
For all this to make sense, I have created a new folder under the Blog
folder/page that already existed, named Tags
. Since this is a dynamic page (meaning that the slug is not a static string but will change every time) I have created a _slug.vue
file on the Tags
folder which will be responsible to display the blogs with the specific tag that I passed to it.
<!-- Tags -> _slug.vue -->
<section class="container mx-auto mt-10">
<h1 class="text-2xl lg:text-4xl font-bold text-center">
Posts tagged with
<span class="text-kt-purple font-bold">#{{ slug }}</span>
</h1>
<div class="text-xl lg:text-2xl underline mt-4 text-center">
<NuxtLink to="/blog/"> All posts </NuxtLink>
</div>
<blog-list v-if="articles.length" :blogs="articles" />
<div v-else class="my-6">
<h2 class="text-xl lg:text-2xl text-center">
Whoops... It seems that there are no articles with #{{ slug }} tag. 😥
</h2>
</div>
</section>
Here, using the same component that I use for the /blog
route, the blog-list
I am able to re-render the blog list but this time I am filtering all the blogs to get the ones that have the specific tag in their Front Matter.
// _slug.vue script
async asyncData({ $content, params }) {
// get the articles where the current tag is included in
// their tag front matter data and their status is published.
const articles = await $content('blog')
.where({
tags: { $contains: params.slug },
status: 'published',
})
.fetch()
const slug = params.slug
return {
articles,
slug,
}
}
Using the content API I am able to filter the blog posts and get the posts that the current tag match their tag declaration in their Front Matter block and they are published!
NOTE: the published is another Front Matter option I added so I can freely create posts whenever I do have an idea or inspiration and I can still push the content in git without them being published, if they are unfinished.
And that's it! Now you can search for specific tags in my blog list and you can filter them for quick access!
The result:
You can find more information about the Nuxt Content module here!
Until the next time ✌