28 August 2020

Nuxt Content module demo with sortable activity

In this article, we zoom in on two of my favourite features of Nuxt content module. We will use Vue components inside markdown file without using any external dependency and complex configurations, and fetch .json data into Nuxt page without using any API setup. Apart from fetching and displaying content, content module allows us to write content in several different formats.

Content Module cheatsheetContent Module cheatsheet

To demonstrate these features, we'll take a look at sorting-activity component, which is a single file component. And we're going to provide data for this component using Nuxt content module. Sorting-activity component can be used in .vue files and .md files as well.

Before we dive in, here is the demo and the Github repo of the sample project.

What is sorting activity?

In eLearning, sorting activity is classified as an interaction that is used to check users' knowledge on a particular topic by asking them to categorise (depending on the differences or similarities) set of cards into their respective groups.

The sorting activity you see in the demo above, is based on such an interaction provided by a popular eLearning authoring tool called Articulate Rise.

Let's see how this component works.

Sorting activity component

drag and drop cards into their respective categorydrag and drop cards into their respective category

Sorting-activity component requires two props, items and categories, where items are draggable cards and categories are droppable targets.

We will write, fetch and provide items and categories as props using Nuxt content module using:

  • markdown files and
  • json files

Here's how the component tag looks like:

// See component at, components/global/GsapSortable.vue
<gsap-sortable :categories="categories" :items="items"></gsap-sortable>

Let's see both features one by one.

Vue component inside markdown

Imagine if you have to add interactive quiz - or activity in this case - to supplement your article content that you've written in markdown!

Say you all your articles are sitting under, /content/articles directory.

| content

For each article, you want to populate the activity with relevant data to match the topic of your article.

With Nuxt modules, we can simply put our components in /components/global/ directory and they will be available for use inside markdown file. This is where we will keep <gsap-sortable> component.

But you may wonder, how can we provide contextual props data for each activity?

Well, with the magic of frontmatter, we can declare items and category data as yaml, like below:

// /content/activities/superhero-acitivty.md
title: Superhero Family
  - label: Marvel Universe
    name: marvel
    list: []
  - label: DC Comics
    name: dc-comics
    list: []
  - name: Superman
    category: dc-comics
  - name: The Hulk
    category: marvel
  - name: Green Lantern
    category: dc-comics
  - name: Iron Man
    category: marvel
  - name: The Flash
    category: dc-comics

And then bind both items and categories variables as props with Vue component that is added in the markdown file.

// /content/activities/superhero-acitivty.md
title: Superhero Family
<gsap-sortable :categories="categories" :items="items"></gsap-sortable>

And there you have it!

So, how we used to do this before the content module?

If you have done this manually, before we had Content module, then you'd know how many dependencies and configurations it took to achive the same result as above.

You'd have used:

  1. frontmatter markdown loader - ...to make Vue components work inside markdown
  2. Prism Js - ...with whole lot of configuration, so that the unstyled code-block doesn't flash upon hard-refresh!
  3. markdownIt - ...if your Vue component is meant to display markdown content inside it.
  4. And you'd have to register all your (global) components - which are meant to be used inside markdown - as a Nuxt plugin, so that they're available in markdown.

I had all four of the above for my own blog, but now, the amazing Content module takes care of all of that for us!

Before Nuxt content moduleBefore Nuxt content module

Take a look at the Articles page of the demo to see this in action.

Fetching json data

Now let's say we want to create a collection of activities that users can interact with back to back.

We can use first option, and define acitivty data in yaml. But if we only need the data, that we would otherwise fetch via an API, then we can certainly use .json to write our data instead.

To do so, we can store all our activity data as .json under the /content folder.

| content

Then, fetch the data using $content into Nuxt page.

export default {
  async asyncData({ $content, params }) {
    const activity = await $content("activities", params.slug).fetch();

    return { activity };

Remember, no body is generated when we fetch .json data using Nuxt content module. We get an object with default keys, such as, dir, slug, path, extension along with the data that's defined in our .json file, i.e. items and categories...

  "dir": "/activities",
  "slug": "sortable-activity-1,
  "path": "/activities/sortable-activity-1",
  "extension": ".json",
  "items": ...,
  "categories": ...

...which we can provide as props to be used with <gsap-sortable> in the template area of the page component.


Take a look at the Learning Acitivties page of the demo to see this in action.

Wrap up

This demostration of Nuxt content module uses only handful of options, but are very impactful and provides an amazing developer experience. Make sure you read Debbie's article on the same topic to see all features in action.

In case you missed it, don't forget to check this printable PDF of Content Module cheatsheet that I published last month.

For more demos and articles on Nuxt, you can follow me on twitter at @KrutiePatel and subscribe to Nuxt Newsletter.