Introducing Learn Storybook : The UI component development tool for React , Vue , Angular
Storybook is a user interface development environment and playground for UI components. The tool enables developers to create components independently and showcase components interactively in an isolated development environment.
Storybook runs outside of the main app so users can develop UI components in isolation without worrying about app specific dependencies and requirements.
Storybook also supports a lot of addons and comes with a flexible API to customize Storybook as desired. A Static version of Storybook can also be built and deployed to an HTTP server
Writing Stories
Here is an example of a basic story: (Let’s assume there’s a component called “Button” in src/components/Button.js
.)
// file: src/stories/index.jsimport React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import Button from '../components/Button';storiesOf('Button', module)
.add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
.add('with some emoji', () => (
<Button onClick={action('clicked')}>
<span role="img" aria-label="so cool">
😀 😎 👍 💯
</span>
</Button>
));
This will add stories in the storybook like this:
This uses Storybook’s basic API for writing stories. There are official and third party Storybook addons for more advanced functionality.
Loading stories dynamically
Sometimes, stories need to be loaded dynamically rather than explicitly in the Storybook config file.
For example, the stories for an app may all be inside the src/components
directory with the .stories.js
extension. It is easier to load all the stories automatically like this inside the .storybook/config.js
file:
import { configure } from '@storybook/react';const req = require.context('../src/components', true, /\.stories\.js$/);function loadStories() {
req.keys().forEach(filename => req(filename));
}configure(loadStories, module);
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
.
The React Native packager resolves all the 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.
Using Decorators
A decorator is a way to wrap a story with a common set of components. Here is an example for centering all components:
import React from 'react';
import { storiesOf } from '@storybook/react';
import MyComponent from '../my_component';storiesOf('MyComponent', module)
.addDecorator(storyFn => <div style={{ textAlign: 'center' }}>{storyFn()}</div>)
.add('without props', () => <MyComponent />)
.add('with some props', () => <MyComponent text="The Comp" />);
This only applies the decorator to the current set of stories. (In this example, the decorator is added only to the MyComponent story group.)
It is possible to apply a decorator globally to all the stories. Here is an example of the Storybook config file:
import React from 'react';
import { configure, addDecorator } from '@storybook/react';addDecorator(storyFn => <div style={{ textAlign: 'center' }}>{storyFn()}</div>);configure(function() {
// ...
}, module);
Using Markdown
As of storybook 3.3, Markdown can be used in Storybook by default. Users can import a markdown file which extracts the raw markdown content into a string. The string can then be used in any addon that supports markdown such as notes and info.
import React from 'react';
import { storiesOf } from '@storybook/react';
import MyComponent from './MyComponent';
import someMarkdownText from './someMarkdownText.md';storiesOf('Component', module).add('With Markdown', () => <MyComponent />, {
notes: { markdown: someMarkdownText },
});
Nesting stories
Stories can be organized in a nested structure using ”/” as a separator:
// file: src/stories/index.jsimport React from 'react';
import { storiesOf } from '@storybook/react';
import Button from '../components/Button';storiesOf('My App/Buttons/Simple', module).add('with text', () => (
<Button onClick={action('clicked')}>Hello Button</Button>
));storiesOf('My App/Buttons/Emoji', module).add('with some emoji', () => (
<Button onClick={action('clicked')}>
<span role="img" aria-label="so cool">
😀 😎 👍 💯
</span>
</Button>
));
Organising stories with titles
Stories can be organized under a title using ”|” as a separator:
import React from 'react';
import { storiesOf } from '@storybook/react';
import Button from '../components/Button';/**
* The Button stories will show up underneath the 'Components' title.
*/
storiesOf('Components|Button', module).add('base', () => (
<Button onClick={() => console.log('Clicked')}>Example Button</Button>
));
If you would prefer to use another character as the separator then you can configure it using the hierarchyRootSeparator
config option. Visit the configuration options parameter page to learn more