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

@storyblok/vue

@storyblok/vue is Storyblok’s official development kit for Vue applications.

Practical resources

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.

src/main.js
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.

src/components/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).

src/components/Page.vue
<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.

src/App.vue
<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

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

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

Repository Playground Opens in new tab

See the repository playground for additional examples.