How to Inline HTML Stories in Storybook 5 Docs
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
heightto 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)

Tyler Sticka has over 20 years of experience designing interfaces for the web and beyond. He co-owns Cloud Four, where he provides multidisciplinary creative direction for a variety of organizations. He’s also an artist, writer, speaker and developer. You can follow Tyler on his personal site, Mastodon or Bluesky.