How to Inline HTML Stories in Storybook 5 Docs
At 4/19/2024
Storybook (the UI component playground we’ve enjoyed using lately) organizes its component examples into stories. These stories are displayed one at a time by default, but the Docs add-on lets you display as many as you’d like in a single page alongside background information, usage details and more.
Docs have two methods for rendering stories:
- Iframe stories render in (you guessed it) an iframe element. Media queries will work as expected and state will be sandboxed, but their height isn’t responsive, and they load rather sluggishly.
- Inline stories render directly in the page you’re viewing, which means they load a lot faster and don’t require
height
to be set. But because Storybook is written in React, this feature only works if our story functions are also written in (or converted to) React.
If you use the HTML “framework” (as we have), you’re limited to iframe stories by default. But we can change that, and with fewer than ten lines of configuration! Here’s how.
Getting started
First, let’s install the handy html-to-react package:
npm i -D html-to-react
Code language: Shell Session (shell)
Next, we import and initialize some dependencies in our .storybook/preview.js
:
import { addParameters } from '@storybook/html';
import { Parser } from 'html-to-react';
const htmlToReactParser = new Parser();
Code language: JavaScript (javascript)
Finally, we use addParameters
to tell the Docs add-on how to parse our story before inlining:
addParameters({
docs: {
prepareForInline: (storyFn) => htmlToReactParser.parse(storyFn()),
},
});
Code language: JavaScript (javascript)
That’s it! Let’s try it out.
Usage
We can now add an inline
property to our stories:
<Story name="Button/Example" inline>
{`<button>Hello world!</button>`}
</Story>
Code language: JavaScript (javascript)
And our button is free of its iframe prison!
This works no matter how the markup string is generated, so template loaders, knobs and more are fair game.
It seems kind of silly to convert plain HTML to a React component, which eventually converts it back to HTML for display. But I’m glad it takes so little custom code to pull off!
Optional: Inline by default
If you find yourself setting inline
on more stories than not, consider enabling Docs’ inlineStories
parameter as well:
addParameters({
docs: {
inlineStories: true,
// ...
},
});
Code language: JavaScript (javascript)
Now stories will render inline by default, without needing an inline
property.
You can disable this for individual stories:
<Story name="Button/Example" inline={false}>
{`<button>Hello world!</button>`}
</Story>
Code language: JavaScript (javascript)
Or for an entire file:
<Meta
title="Button"
parameters={{ docs: { inlineStories: false } }}
/>
Code language: JavaScript (javascript)