Storyblok
Search Storyblok's Documentation
  1. @storyblok/nuxt

@storyblok/nuxt

@storyblok/nuxt is Storyblok’s official development kit for Nuxt applications.

Practical resources

Requirements

  • Nuxt 3.0 or later
  • Node.js LTS (version 22.x recommended)
  • Modern web browser (e.g., Chrome, Firefox, Safari, Edge – latest versions)

Installation

Add the package to a project by running this command in the terminal:

npm install @storyblok/nuxt@latest

Usage

Configuration

Import and initialize the SDK using the access token of a Storyblok space.

nuxt.config.ts
import { defineNuxtConfig } from 'nuxt';

export default defineNuxtConfig({
	modules: [
		[
			'@storyblok/nuxt',
			{
				accessToken: 'YOUR_ACCESS_TOKEN',
				apiOptions: {
					region: 'eu',
				},
			},
		],
	],
});

Learn how to retrieve an access token in the access tokens concept.

The region parameter must be specified unless the space was created in the EU. Learn more in the @storyblok/js package reference.

Components

Create a Nuxt component for each block defined in Storyblok. Each component will receive a blok prop, containing the content of the block.

storyblok/Feature.vue
<script setup>
defineProps({ blok: Object })
</script>

<template>
  <div v-editable="blok">
    <h2>{blok.headline}</h2>
  </div>
</template>

Use <StoryblokComponent> to automatically render nested components (provided they are registered globally).

storyblok/Page.vue
<script setup>
defineProps({ blok: Object })
</script>

<template>
	<main>
		<StoryblokComponent v-for="currentBlok in blok.body":key="currentBlok._uid" :blok="currentBlok" />
	</main>
</template>

Components created in the storyblok folder are loaded automatically and do not need to be imported.

Fetching and rendering

In a Nuxt page or component, use the one-liner composable useAsyncStoryblok to fetch a story and render the content with the StoryblokComponent element.

pages/index.vue
<script setup>
	const story = await useAsyncStoryblok(
	  "home",
	  { version: "draft", resolve_relations: "featured-articles.posts" },
	  { resolveRelations: ["featured-articles.posts"]},
	);
</script>

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

API

storyblok

Import and initialize the SDK to access and configure all features.

import { defineNuxtConfig } from 'nuxt';

export default defineNuxtConfig({
	modules: [['@storyblok/nuxt', OPTIONS]],
});

Alternative syntax:

import { defineNuxtConfig } from 'nuxt';

export default defineNuxtConfig({
	modules: ['@storyblok/nuxt'],
	storyblok: OPTIONS,
});

All options listed in the @storyblok/vue package reference are available. The following additional options are available:

Key

Description

Type

componentsDir

Define a custom directory other than storyblok as the location of components.

string

enableSudoMode

See example below.

boolean

Example: enableSudoMode

To include additional functionalities in the apiOptions, such as custom cache methods, implement the following inside the plugins folder:

plugins/storyblok.js
import { apiPlugin, StoryblokVue } from '@storyblok/vue';

export default defineNuxtPlugin(({ vueApp }) => {
  vueApp.use(StoryblokVue, {
    accessToken: '<access-token>',
    apiOptions: {
      cache: {
        type: 'custom',
        custom: {
          flush() {
            console.log('done');
          }
        }
      }
    },
    use: [apiPlugin]
  });

StoryblokVue

If desired, import and use StoryblokVue to create a custom Nuxt plugin as shown in the enableSudoMode example above.

apiPlugin

apiPlugin configures the implementation of the Storyblok API. It is imported from @storyblok/js.

import { apiPlugin } from '@storyblok/nuxt';
import { defineNuxtConfig } from 'nuxt';

export default defineNuxtConfig({
	modules: [
		[
			'@storyblok/nuxt',
			{
				accessToken: '<your-access-token>',
				use: [apiPlugin],
			},
		],
	],
});

For more information, see the @storyblok/js package reference.

useAsyncStoryblok

Using this one-liner composable, enable both data fetching and bridge capabilities. This is the recommended option, as it supports both server-side rendering (SSR) and static site generation (SSG).

<script setup>
	const { story } = await useAsyncStoryblok(URL, API_OPTIONS, BRIDGE_OPTIONS);

	if (story.value.status) {
	  throw createError({
	    statusCode: story.value.status,
	    statusMessage: story.value.response
	  });
	}
</script>

For the API_OPTIONS, see the storyblok-js-client package reference. For the BRIDGE_OPTIONS, see the StoryblokBridge reference.

useStoryblok

Enable both data fetching and bridge capabilities using this composable. Recommended only for client-side rendering (CSR).

<script setup>
	import { useStoryblok } from '@storyblok/vue';
	const { story, fetchState } = await useStoryblok(URL, API_OPTIONS, BRIDGE_OPTIONS);
</script>

For the API_OPTIONS, see the storyblok-js-client package reference. For the BRIDGE_OPTIONS, see the StoryblokBridge reference.

useStoryblokApi

useStoryblokApi() returns the client instantiated in the application.

<script setup>
	import { useStoryblokApi } from '@storyblok/nuxt';

	const storyblokApi = useStoryblokApi();
	const { data } = await storyblokApi.get(URL, API_OPTIONS)
</script>

For the API_OPTIONS, see the storyblok-js-client package reference.

useStoryblokBridge

useStoryblokBridge() activates the Storyblok Bridge.

<script setup>
	import { useStoryblokApi, useStoryblokBridge } from '@storyblok/nuxt';

	const storyblokApi = useStoryblokApi();
	const { data } = await storyblokApi.get(URL, API_OPTIONS);

	onMounted(() => {
		useStoryblokBridge(STORY_ID, CALLBACK, BRIDGE_OPTIONS);
	});
</script>

For the BRIDGE_OPTIONS, see the StoryblokBridge reference.

StoryblokComponent

This component automatically renders Storyblok blocks for corresponding Vue components registered in the application. It requires a blok property. Any additional passed properties are forwarded to the Vue component.

<StoryblokComponent :blok="story.content" />

Use it to iterate over blocks fields as follows:

<StoryblokComponent
	v-for="currentBlok in blok.body"
	:key="currentBlok._uid"
	:blok="currentBlok"
/>

v-editable

Use the v-editable directive in components to connect them to the Storyblok Bridge.

<script setup>
	defineProps({ blok: Object });
</script>

<template>
	<section v-editable="blok">
		<h3>{{ blok.name }}</h3>
	</section>
</template>

StoryblokRichText

Used to render a rich text field from a story.

<StoryblokRichText :doc="blok.richtext_field" />

See further options in the @storyblok/richtext package reference.

Example: Overriding default resolvers

<script setup>
  import { NuxtLink } from '#components';
  import type { StoryblokRichTextNode } from '@storyblok/vue';
  import CodeBlok from "./components/CodeBlok.vue";

  const resolvers = {
    // NuxtLink example:
    [MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
      h(NuxtLink, {
        to: node.attrs?.href,
        target: node.attrs?.target,
      }, node.text),
    // Custom code block component example:
    [BlockTypes.CODE_BLOCK]: (node: Node) => {
      return h(CodeBlock, {
        class: node?.attrs?.class,
      }, node.children)
    },
  }
</script>

<template>
  <StoryblokRichText :doc="blok.richtext_field" :resolvers="resolvers" />
</template>

useStoryblokRichText

Use this composable to programmatically render a rich text field.

<script setup>
	import { useStoryblokRichText } from '@storyblok/vue';
	const { render } = useStoryblokRichText(RICH_TEXT_OPTIONS);

	const content = render(blok.articleContent);
</script>

<template>
	<div v-html="content"></div>
</template>

See further options in the @storyblok/richtext package reference.

Example: Overriding default resolvers

<script setup>
  import CodeBlok from "./components/CodeBlok.vue";

  const { render } = useStoryblokRichText({
    resolvers: {
      // NuxtLink example:
      [MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
        h(NuxtLink, {
          to: node.attrs?.href,
          target: node.attrs?.target,
        }, node.text),
      // Custom code block component example:
      [BlockTypes.CODE_BLOCK]: (node: Node) =>
        h(CodeBlock, {
          class: node?.attrs?.class,
        }, node.children)
    }
  });

  const root = () => render(blok.articleContent);
</script>

Further resources

Repository Playground Opens in new tab

See the repository playground for additional examples.