Almost EVERYONE who tried headless systems said they saw benefits. Download the state of CMS now!

Storyblok now on AWS Marketplace: Read more

O’Reilly Report: Decoupled Applications and Composable Web Architectures - Download Now

Empower your teams & get a 582% ROI: See Storyblok's CMS in action

Skip to main content

Render Storyblok Stories Dynamically in Nuxt

Try Storyblok

Storyblok is the first headless CMS that works for developers & marketers alike.

Having successfully integrated Storyblok into our Nuxt app in the last tutorial, let’s know take it one step further and add dynamically rendered pages as well as a page layout.

Live demo:

If you’re in a hurry, have a look at our live demo in Stackblitz! Alternatively, you can explore or fork the code from the Nuxt Ultimate Tutorial GitHub Repository.

Section titled Requirements Requirements

This tutorial is part 2 of the Ultimate Tutorial Series for Nuxt. We recommend that you follow the previous tutorial before starting this one.

Section titled Creating a Layout Creating a Layout

Before creating additional pages in Storyblok, let’s first of all create a layout in our Nuxt app. This layout should include a header bar and a primary navigation for our website – because having multiple pages without being able to navigate between them doesn’t make much sense, does it?

So let’s start by creating a header component. Since this won’t have a corresponding blok in our Storyblok space, we’ll create it in the components folder:

components/Header.vue
        
      <template>
  <header class="w-full h-24 bg-[#f7f6fd]">
    <div class="container h-full mx-auto flex items-center justify-between">
      <NuxtLink to="/">
        <h1 class="text-[#50b0ae] text-3xl font-bold">Storyblok Nuxt</h1>
      </NuxtLink>
      <nav>
        <ul class="flex space-x-8 text-lg font-bold">
          <li>
            <NuxtLink to="/blog" class="hover:text-[#50b0ae]">Blog</NuxtLink>
          </li>
          <li>
            <NuxtLink to="/about" class="hover:text-[#50b0ae]">About</NuxtLink>
          </li>
        </ul>
      </nav>
    </div>
  </header>
</template>
    

Now we can implement this header component in our layout. Fortunately, Nuxt allows us to create layouts very easily. All we have to do is to create a default.vue in a layouts folder with the following content:

layouts/default.vue
        
      <template>
  <main>
    <Header />
    <slot />
  </main>
</template>
    

And that’s it! If you take a look at your project running on https://localhost:3000 now, you’ll see your header component:


Nuxt Layout rendered correctly

Nuxt Layout rendered correctly

Section titled Rendering Pages dynamically Rendering Pages dynamically

Before actually creating any new pages in the Storyblok space, let’s take care of the required logic on the frontend side.

Once again, Nuxt makes it extremely easy for you. All we have to do is to delete our pages/index.vue and replace it with a pages/[...slug].vue.

pages/[...slug].vue
        
      <script setup>
const { slug } = useRoute().params

const story = await useAsyncStoryblok(
  slug && slug.length > 0 ? slug.join('/') : 'home',
  { version: 'draft' }
)
</script>

<template>
  <StoryblokComponent v-if="story" :blok="story.content" />
</template>

    

So, what’s happening here? We’re dynamically getting the current slug via the useRoute function. This is then passed as a parameter to the useAsyncStoryblok function. If the slug is empty, we want our Home story to be displayed.

Section titled Adding Pages in Storyblok Adding Pages in Storyblok

With our logic being complete, we can now add our Blog and About pages in our Storyblok space! To do that, simply go to Content {1}, Create new {2}, and then Choose Story {3}.

Adding a story
1
2
3

Adding a story

Now you can provide a name {1} – the slug will be filled out automatically for you. Let’s start with the About page.

Configuring a new story
1

Configuring a new story

Once the page is created, you can add nestable bloks to it. Simply click on the Plus Icon {1} and add a Teaser component {2}.

Inserting a new block
1
2

Inserting a new block

Now you can enter any headline you want for your newly created About page:

New block rendering correctly on the About page

New block rendering correctly on the About page

Try to repeat the same process on your own for the Blog page.

Section titled Bonus: Highlighting the currently active navigation item Bonus: Highlighting the currently active navigation item

If you click on the navigation entries in our Header component, everything already works as expected. Let’s take it a little further by highlighting the currently active navigation item. Yet again, this is extremely easy to accomplish in Nuxt because it automatically adds a router-link-active class to your links! Let’s utilize it by adding the following styles to the Header component:

components/Header.vue
        
      <style scoped>
nav a.router-link-active {
  @apply underline underline-offset-4 decoration-4 decoration-[#50b0ae];
}
</style>
    

Section titled Wrapping Up Wrapping Up

Congratulations! You have created your first pages in Storyblok and they are rendered in your Nuxt app dynamically – how cool is that!?

Next Part:

Continue reading and find out How to create Dynamic Menus in Storyblok and Nuxt. Not interested in dynamic menus? Feel free to skip this part and learn How to Create Custom Components in Storyblok and Nuxt.

Author

Manuel Schröder

Manuel Schröder

Manuel is a front-end engineer who loves crafting beautiful and fast websites. International Relations graduate turned WordPress expert, he ultimately developed a passion for the Jamstack. His favorite technologies include Vue, Astro, Tailwind, and Storyblok. These days, Manuel works as a Developer Relations Engineer at Storyblok.