Writing Stories
A Storybook is a collection of stories. Each story represents a single visual state of a component.
Technically, a story is a function that returns something that can be rendered to screen.
Basic story
Here is an example of stories for a Button
component:
This is what you’ll see in Storybook:
The named exports define the Button’s stories, and the default
export defines metadata that applies to the group. In this case, the component
is Button
. The title
determines the title of the group in Storybook’s left-hand navigation panel and should be unique, i.e. not re-used across files. In this case it’s located at the top level, but typically it’s positioned within the story hierarchy.
This example is written in Storybook’s Component Story Format (CSF). Storybook also supports:
- a classic storiesOf API, which adds stories through Storybook’s API.
- an experimental MDX syntax, which mixes longform Markdown docs and JSX stories.
Since CSF is a new addition to Storybook, most Storybook examples you’ll find in the wild are written to the storiesOf API.
Furthermore, Storybook for React Native currently only supports the storiesOf
format. React Native will get CSF and MDX support in a future release.
Story file location
Stories are easier to maintain when they are located alongside the components they document. We recommend:
It’s up to you to find a naming/placing scheme that works for your project/team. Other naming conventions:
stories sub-directory in component directory
stories directory outside src directory
Loading stories
Stories are loaded in the .storybook/main.js
file or .storybook/preview.js
file.
The most convenient way to load stories is by filename. For example, if your stories files are located in the src/components
directory, you can use the following snippet:
Alternatively you can import all your stories in .storybook/preview.js
:
NOTE: The
configure
function should be called only once in.storybook/preview.js
.
The configure
function accepts:
- A single
require.context
”req
” - An array of
req
s to load from multiple locations - A loader function that should return void or an array of module exports
If you want to load from multiple locations, you can use an array:
Or if you want to do some custom loading logic, you can use a loader function. Just remember to return an array of module exports if you want to use Component Story Format. Here’s an example that forces files to load in a specific order.
Here’s another example that mixes manual loading with glob-style loading:
Storybook uses Webpack’s require.context to load modules dynamically. Take a look at the relevant Webpack docs to learn more about how to use require.context
.
If you are using the storiesOf
API directly, or are using @storybook/react-native
where CSF is unavailable, you should use a loader function with no return value:
Furthermore, the React Native packager resolves all imports at build-time, so it’s not possible to load modules dynamically. There is a third party loader react-native-storybook-loader to automatically generate the import statements for all stories.
Decorators
A decorator is a way to wrap a story with a common set of components, for example if you want to wrap a story in some formatting, or provide some context to the story.
Decorators can be applied globally, at the component level, or individually at the story level. Global decorators are typically applied in the Storybook config files, and component/story decorators are applied in the story file.
Here is an example of a global decorator which centers every story in the .storybook/preview.js
:
* In Vue projects you have to use the special component
<story/>
instead of the function parameterstoryFn
that is used in React projects, even if you are using JSX, for example:
And here’s an example of component/local decorators. The component decorator wraps all the stories in a yellow frame, and the story decorator wraps a single story in an additional red frame.
Decorators are not only for story formatting, they are generally useful for any kind of context needed by a story.
- Theming libraries require a theme to be passed in through context. Rather than redefining this in every story, add a decorator.
- Likewise, state management libraries like Redux provide a global data store through context.
- Finally, Storybook addons heavily use decorators. For example, the Storybook’s Knobs addon uses decorators to modify the input properties of the story based on a UI.
Parameters
Parameters are custom metadata for a story. Like decorators, they can also be hierarchically applied: globally, at the component level, or locally at the story level.
Here’s an example where we are annotating our stories with Markdown notes using parameters, to be displayed in the Notes addon.
We first apply some notes globally in the .storybook/preview.js
.
This would make sense if, for example, instructions.md
contained instructions on how to document your components when there is no documentation available.
Then for components that did have documentation, we might override it at the component/story level:
In this example, the small
and medium
stories get the component notes documented in notes.md
(as opposed to the generic instructions in instructions.md
). The special
story gets some special notes.
Searching
By default, search results will show up based on the file name of your stories. As of storybook 5, you can extend this with notes
to have certain stories show up when the search input contains matches. For example, if you built a Callout
component that you want to be found by searching for popover
or tooltip
as well, you could use notes
like this:
Story hierarchy
Stories can be organized in a nested structure using ”/” as a separator.
For example the following snippets nest the Button
and Checkbox
components within the Atoms
group, under a top-level heading called Design System
.
By default the top-level heading will be treated as any other group, but if you’d like it to be given special emphasis as a “root”, use the showRoots
config option. See the
configuration options parameter page to learn more.
Generating nesting path based on __dirname
Nesting paths can be programmatically generated with template literals because story names are strings.
One example would be to use base
from paths.macro
:
This uses babel-plugin-macros.
Run multiple storybooks
Multiple storybooks can be built for different kinds of stories or components in a single repository by specifying different port numbers in the start scripts:
Permalinking to stories
Sometimes you might wish to change the name of a story or its position in the hierarchy, but preserve the link to the story or its documentation. Here’s how to do it.
Consider the following story:
Storybook’s ID-generation logic will give this the ID foo-bar--baz
, so the link would be ?path=/story/foo-bar--baz
.
Now suppose you want to change the position in the hierarchy to OtherFoo/Bar
and the story name to Moo
. Here’s how to do that:
Storybook will prioritize the id
over the title for ID generation, if provided, and will prioritize the story.name
over the export key for display.