@storyblok/vue
@storyblok/vue is Storyblok’s official development for Vue applications.
Practical resources
Section titled “Practical resources”Requirements
Section titled “Requirements”- Vue version 3.4 or later
- Node.js LTS (version 22.x recommended)
- Modern web browser (e.g., Chrome, Firefox, Safari, Edge – latest versions)
Installation
Section titled “Installation”Add the package to a project by running this command in the terminal:
npm install @storyblok/vue@latest
Configuration
Section titled “Configuration”Import and initialize the SDK using the access token of a Storyblok space.
import { createApp } from "vue";import { StoryblokVue, apiPlugin } from "@storyblok/vue";import App from "./App.vue";
const app = createApp(App);
app.use(StoryblokVue, { accessToken: "YOUR_ACCESS_TOKEN", use: [apiPlugin], apiOptions: { region: "eu", },});
app.component("Page", Page);app.component("Feature", Feature);
app.mount("#app");
Components
Section titled “Components”Create a Vue component for each block defined in Storyblok and registered in the configuration. 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>
Using slots
Section titled “Using slots”You can use slots to insert content into the dynamic component:
<template> <StoryblokComponent v-if="story" :blok="story.content"> <MyCustomComponent /> </StoryblokComponent></template>
Then, in the dynamic component that StoryblokComponent
uses, you can render the slot content as you would with regular Vue slots:
<template> <div> <!-- Some content -->
<!-- The slot content MyCustomComponent will be rendered here --> <slot></slot>
<!-- Some more content --> </div></template>
Fetching and rendering
Section titled “Fetching and rendering”In a Vue component, use the client to fetch a story and render the content using StoryblokComponent
.
<script setup> import { useStoryblokApi } from '@storyblok/vue';
const storyblokApi = useStoryblokApi(); const { data } = await storyblokApi.get('cdn/stories/home', { version: 'draft', }); const { story } = data;</script>
<template> <StoryblokComponent v-if="story" :blok="story.content" /></template>
StoryblokVue
Section titled “StoryblokVue”Import and initialize the SDK to access and configure all features.
import { createApp } from "vue";import { StoryblokVue } from "@storyblok/vue";import App from "./App.vue";import MyCustomFallback from "./components/MyCustomFallback.vue";
const app = createApp(App);
app.use(StoryblokVue, { // ... enableFallbackComponent: true, customFallbackComponent: "MyCustomFallback",});
app.component("MyCustomFallback", MyCustomFallback);
All options listed in the @storyblok/js package reference are available. The following additional options are available:
Key | Description | Type |
---|---|---|
enableFallbackComponent | Enable or disable a fallback component to be rendered if no Vue component has been defined for a Storyblok block. Disabled by default. | boolean |
customFallbackComponent | Register a custom fallback component. Requires enableFallbackComponent to be enabled. See example below. | string |
Example: customFallbackComponent
Section titled “Example: customFallbackComponent”import MyCustomFallback from "./components/MyCustomFallback.vue";
app.use(StoryblokVue, { // ... enableFallbackComponent: true, customFallbackComponent: "MyCustomFallback",});
app.component("MyCustomFallback", MyCustomFallback);
apiPlugin
Section titled “apiPlugin”apiPlugin
configures the implementation of the Storyblok API. It is imported from @storyblok/js
.
import { StoryblokVue, apiPlugin } from "@storyblok/vue";
app.use(StoryblokVue, { use: [apiPlugin],});
See the @storyblok/js reference for further details.
useStoryblok
Section titled “useStoryblok”Enable both data fetching and bridge capabilities using this composable.
<script setup> import { useStoryblok } from "@storyblok/vue"; const { story, fetchState } = useStoryblok(URL, API_OPTIONS, BRIDGE_OPTIONS);</script>
For the API_OPTIONS
, see the storyblok-js-client reference. For the BRIDGE_OPTIONS
, see the @storyblok/preview-bridge reference.
useStoryblokApi
Section titled “useStoryblokApi”useStoryblokApi()
returns the client instantiated in the application.
<script setup> import {useStoryblokApi} from '@storyblok/vue'; const storyblokApi = useStoryblokApi(); const {data} = await storyblokApi.get(URL, API_OPTIONS)</script>
For the API_OPTIONS
, see the storyblok-js-client reference.
useStoryblokBridge
Section titled “useStoryblokBridge”useStoryblokBridge()
activates the Storyblok Bridge.
<script setup> import {useStoryblokApi, useStoryblokBridge} from '@storyblok/vue'; const storyblokApi = useStoryblokApi(); const {data} = await storyblokApi.get(URL, API_OPTIONS); useStoryblokBridge(STORY_ID, CALLBACK, BRIDGE_OPTIONS);</script>
For the BRIDGE_OPTIONS
, see the @storyblok/preview-bridge reference.
StoryblokComponent
Section titled “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.
Use it to iterate over blocks fields as follows:
<StoryblokComponent v-for="currentBlok in blok.nested_bloks" :key="currentBlok._uid" :blok="currentBlok"/>
v-editable
Section titled “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
Section titled “StoryblokRichText”Used to render a rich text field from a story.
<StoryblokRichText :doc="blok.richtext_field" />
See the @storyblok/richtext reference for further details.
Example: Override default resolvers
Section titled “Example: Override default resolvers”<script setup> import { type VNode, h } from "vue"; import { StoryblokRichText, BlockTypes, MarkTypes, type StoryblokRichTextNode } from "@storyblok/vue"; import { RouterLink } from "vue-router"; import CodeBlok from "./components/CodeBlok.vue";
const resolvers = { // RouterLink example: [MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) => { return node.attrs?.linktype === 'STORY' ? h(RouterLink, { to: node.attrs?.href, target: node.attrs?.target, }, node.text) : h('a', { href: 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.articleContent" :resolvers="resolvers" /></template>
useStoryblokRichText
Section titled “useStoryblokRichText”Use this composable to programmatically render a rich text field.
<StoryblokRichText :doc="blok.richtext_field" />
See the @storyblok/richtext reference for further details.
Example: Override default resolvers
Section titled “Example: Override default resolvers”<script setup> import { type VNode, h } from "vue"; import { StoryblokRichText, BlockTypes, MarkTypes, type StoryblokRichTextNode } from "@storyblok/vue"; import { RouterLink } from "vue-router"; import CodeBlok from "./components/CodeBlok.vue";
const resolvers = { // RouterLink example: [MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) => { return node.attrs?.linktype === 'STORY' ? h(RouterLink, { to: node.attrs?.href, target: node.attrs?.target, }, node.text) : h('a', { href: 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.articleContent" :resolvers="resolvers" /></template>
Further resources
Section titled “Further resources”Get in touch with the Storyblok community