Skip to content

@storyblok/react (Version 6.x)

@storyblok/react is Storyblok’s official SDK for React applications.

  • React version 17 or later
  • Node.js LTS (version 22.x recommended)
  • Modern web browser (for example, Chrome, Firefox, Safari, or Edge)

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

Terminal window
npm install @storyblok/react@6
Export When to use How to use
@storyblok/react Client-rendered and single-page apps. Use useStoryblok and StoryblokComponent.
@storyblok/react/ssr Static rendering and static export (including Next.js output: 'export'). Live editing isn’t supported. Use StoryblokServerStory for rendering components. The Storyblok Bridge isn’t loaded.
@storyblok/react/rsc Next.js App Router and other React Server Components setups. Use StoryblokStory in Server Components so the Storyblok Bridge and live editing work in the Visual Editor. Use StoryblokServerComponent for nested blocks and StoryblokComponent in Client Components.

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

src/main.jsx
import { apiPlugin, storyblokInit } from "@storyblok/react";
import Page from "./Page.js";
import Feature from "./Feature.js";
storyblokInit({
accessToken: "YOUR_ACCESS_TOKEN",
use: [apiPlugin],
apiOptions: {
region: "eu",
},
components: {
page: Page,
feature: Feature,
},
});

Create a React component for each block defined in Storyblok and registered in the configuration. Each component receives a blok prop that contains the content of the block.

const Feature = ({ blok }) => (
<div>
<h2>{blok.headline.text}</h2>
</div>
);
export default Feature;

Use <StoryblokComponent> to automatically render nested components (provided the configuration registers the nested components).

src/storyblok/Page.jsx
import { StoryblokComponent } from "@storyblok/react";
export default function Page({ blok }) {
return <section>{blok.body ? blok.body.map((blok) => <StoryblokComponent blok={blok} key={blok._uid} />) : null}</section>;
}

Use the client to fetch a story and render the content using StoryblokComponent.

src/App.jsx
import { StoryblokComponent, useStoryblok } from "@storyblok/react";
export default function App() {
const story = useStoryblok("home", {
version: "draft",
});
if (!story?.content) {
return <div>Loading...</div>;
}
return <StoryblokComponent blok={story.content} />;
}

@storyblok/react exports the following functions, hooks, and components.

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

import { storyblokInit } from "@storyblok/react";
storyblokInit(OPTIONS);

storyblokInit() creates an instance of the Storyblok API client and loads the Storyblok Bridge.

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

Key Description Type
components An object that maps React components to Storyblok blocks. Each component receives a blok prop containing the content of the block. object
enableFallbackComponent Enable or disable a fallback component that renders when a Storyblok block has no React component. Disabled by default. boolean
customFallbackComponent Register a custom fallback component. Requires enableFallbackComponent. React component

apiPlugin configures the implementation of the Storyblok API. The plugin comes from @storyblok/js.

import { storyblokInit, apiPlugin } from "@storyblok/react";
storyblokInit({ use: [apiPlugin] });

Learn more in the @storyblok/js reference.

Enable both data fetching and Storyblok Bridge capabilities with useStoryblok.

import { useStoryblok } from "@storyblok/react";
export default function App() {
const story = useStoryblok(URL, API_OPTIONS, BRIDGE_OPTIONS);
}

For the API_OPTIONS, refer to the storyblok-js-client reference. For the BRIDGE_OPTIONS, refer to the @storyblok/preview-bridge reference.

useStoryblokApi() returns the client instantiated in the application.

import { useStoryblokApi } from "@storyblok/react";
import { useEffect, useState } from "react";
export default function App() {
const storyblokApi = useStoryblokApi();
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
const response = await storyblokApi.get(URL, API_OPTIONS);
setData(response.data);
}
fetchData();
}, []);
}

For the API_OPTIONS, refer to the storyblok-js-client reference.

getStoryblokApi() is an alias of useStoryblokApi().

useStoryblokBridge() activates the Storyblok Bridge.

import { useStoryblokApi, useStoryblokBridge } from "@storyblok/react";
import { useEffect, useState } from "react";
export default function App() {
const storyblokApi = useStoryblokApi();
const [data, setData] = useState(null);
useEffect(() => {
async function fetchData() {
const response = await storyblokApi.get(URL, API_OPTIONS);
setData(response.data);
}
fetchData();
}, []);
useStoryblokBridge(STORY_ID, CALLBACK, BRIDGE_OPTIONS);
}

For the BRIDGE_OPTIONS, refer to the @storyblok/preview-bridge reference.

To access the Storyblok Bridge via window instead of useStoryblokBridge, use the following code:

const storyblokBridge = new window.StoryblokBridge(options);
storyblokBridge.on(["input", "published", "change"], (event) => {
// ...
});

registerStoryblokBridge() is an alias of useStoryblokBridge().

Activates the Storyblok Bridge on the window.

loadStoryblokBridge();

useStoryblokState() accepts a story from the Storyblok API and makes the story reactive for live editing.

import { useStoryblokState } from "@storyblok/react";
export default function Home({ story: STORY_OBJECT }) {
const story = useStoryblokState(STORY_OBJECT);
if (!story.content) {
return <div>Loading...</div>;
}
}

StoryblokStory maintains the state of a story and uses StoryblokComponent to render the route components dynamically, using the list of components loaded via storyblokInit. Use StoryblokComponent inside components to render nested components dynamically.

StoryblokStory accepts a story from the Storyblok API and Storyblok Bridge options.

<StoryblokStory story={STORY_OBJECT} bridgeOptions={BRIDGE_OPTIONS} />

For the BRIDGE_OPTIONS, refer to the @storyblok/preview-bridge reference.

StoryblokComponent is a React component that dynamically renders blocks from Storyblok.

StoryblokComponent accepts a blok prop, which should be a block from the Storyblok API. StoryblokComponent passes any other props directly to the block component.

<StoryblokComponent blok={blok} />

Use StoryblokComponent to iterate over block fields as follows:

{
blok.nested_bloks?.map((currentBlok, index) => <StoryblokComponent blok={currentBlok} key={currentBlok._uid || index} />);
}

Use StoryblokServerComponent rather than StoryblokComponent when using React Server Components.

storyblokEditable() accepts a block from the Storyblok API and returns an object containing the HTML attributes to make elements editable in the Storyblok Visual Editor. Learn more in the @storyblok/js reference.

const Feature = ({ blok }) => {
return (
<section {...storyblokEditable(blok)} key={blok._uid}>
{blok.title}
</section>
);
};

setComponents() updates the component map of the current client instance.

setComponents(COMPONENTS_OBJECT);

Used to render a rich text field from a story.

<StoryblokRichText doc={blok.richtext_field} />

Learn more in the @storyblok/richtext reference.

Section titled “Example: custom links with the Next.js Link component”

Use asTag to render a Next.js Link component for internal story links:

import { Mark } from "@tiptap/core";
import { asTag } from "@storyblok/react";
import Link from "next/link";
const CustomLink = Mark.create({
name: "link",
renderHTML({ HTMLAttributes }) {
if (HTMLAttributes.linktype === "story") {
return [asTag(Link), { href: HTMLAttributes.href }, 0];
}
return ["a", { href: HTMLAttributes.href, target: HTMLAttributes.target }, 0];
},
});
function App() {
return <StoryblokRichText doc={blok.richtext_field} tiptapExtensions={{ link: CustomLink }} />;
}

Use StoryblokServerRichText rather than StoryblokRichText when using React Server Components.

Use useStoryblokRichText to programmatically render a rich text field.

import { useStoryblokRichText } from "@storyblok/react";
function App() {
const { render } = useStoryblokRichText({});
const root = () => render(blok.articleContent);
return <>{root()}</>;
}

Learn more in the @storyblok/richtext reference.

import Heading from "@tiptap/extension-heading";
import { useStoryblokRichText } from "@storyblok/react";
const CustomHeading = Heading.extend({
renderHTML({ node, HTMLAttributes }) {
const level = node.attrs.level;
return [`h${level}`, { class: `heading-${level}`, ...HTMLAttributes }, 0];
},
});
function App() {
const { render } = useStoryblokRichText({
tiptapExtensions: { heading: CustomHeading },
});
const root = () => render(blok.articleContent);
return <>{root()}</>;
}

Last updated:

Was this page helpful?

What went wrong?

This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.