@storyblok/vue
@storyblok/vue is Storyblok’s official development kit for Vue applications.
Practical resources
- Vue Guide
See the Vue guide for a comprehensive walkthrough on integrating Storyblok with Vue.
- Space Blueprint: Vue Opens in new tab
See the blank space blueprint for Vue to kickstart a new project.
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
Add the package to a project by running this command in the terminal:
npm install @storyblok/vue@latest
Usage
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');
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 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>
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>
API
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';
const app = createApp(App);
app.use(StoryblokVue, OPTIONS);
All options listed in the @storyblok/js package reference are available. The following additional options are available:
Key | Description | Type |
---|---|---|
| Enable or disable a fallback component to be rendered if no Vue component has been defined for a Storyblok block. Disabled by default. | boolean |
| Register a custom fallback component. Requires | string |
Example: customFallbackComponent
import MyCustomFallback from './components/MyCustomFallback.vue';
app.use(StoryblokVue, {
// ...
enableFallbackComponent: true,
customFallbackComponent: 'MyCustomFallback',
});
app.component('MyCustomFallback', MyCustomFallback);
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],
});
For more information, see the @storyblok/js package reference.
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 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/vue';
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/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 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.nested_bloks"
: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 { 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
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 { type VNode, h } from "vue";
import { useStoryblokRichText, BlockTypes, MarkTypes, type StoryblokRichTextNode } from "@storyblok/vue";
import { RouterLink } from "vue-router";
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)
},
}
const { render } = useStoryblokRichText({
resolvers,
})
const root = () => render(blok.articleContent);
</script>
<template>
<root />
</template>
Further resources
See the repository playground for additional examples.