Render Storyblok Stories Dynamically in Nuxt

Contents
    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!

    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.

    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:

    https://localhost:3000
    Storyblok editing capabilities

    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 useStoryblok(slug ? slug : '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 useStoryblok function. If the slug is empty, we want our Home story to be displayed.

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

    app.storyblok.com
    Storyblok editing capabilities
    1
    2
    3

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

    app.storyblok.com
    Storyblok editing capabilities
    1

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

    app.storyblok.com
    Storyblok editing capabilities
    1
    2

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

    app.storyblok.com
    Storyblok editing capabilities

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

    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>

    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.

    Resource Link
    Storyblok Nuxt 3 Ultimate Tutorial https://www.storyblok.com/tp/storyblok-nuxt-ultimate-tutorial
    Storyblok Nuxt 3 Module https://github.com/storyblok/storyblok-nuxt
    Storyblok Nuxt Technology Hub https://www.storyblok.com/tc/nuxtjs
    Storyblok APIs https://www.storyblok.com/docs/api
    Nuxt 3 https://v3.nuxtjs.org/

    Developer Newsletter

    Want to stay on top of the latest news and updates in Storyblok?
    Subscribe to Code & Bloks - our headless newsletter.

    An error occurred. Please get in touch with marketing@storyblok.com

    Please select at least one option.

    Please enter a valid email address.

    This email address is already registered.

    Please Check Your Email!

    Almost there! To confirm your subscription, please click on the link in the email we’ve just sent you. If you didn’t receive the email check your ’junk folder’ or