@storyblok/nuxt
@storyblok/nuxt is Storyblok’s official development kit for Nuxt applications.
Practical resources
- Nuxt Guide
See the Nuxt guide for a comprehensive walkthrough on integrating Storyblok with Nuxt.
- Space Blueprint: Nuxt Opens in new tab
See the blank space blueprint for Nuxt to kickstart a new project.
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.
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.
<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).
<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.
<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 |
---|---|---|
| Define a custom directory other than | string |
| 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:
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
See the repository playground for additional examples.