Storybook lets us prototype components easily with various parameters.
In this article, we’ll look at how to write and browse stories with Storybook.
Decorators
We can add decorators with the decorators
property.
It’s used to wrap our component with our own markup.
For example, we can write:
src/stories/Button.js
import React from 'react';
import PropTypes from 'prop-types';
import './button.css';
export const Button = ({ primary, backgroundColor, size, label, ...props }) => {
const mode = primary ? 'button-primary' : 'button-secondary';
return (
<button
type="button"
className={['button', `button-${size}`, mode].join(' ')}
style={backgroundColor && { backgroundColor }}
{...props}
>
{label}
</button>
);
};
Button.propTypes = {
primary: PropTypes.bool,
backgroundColor: PropTypes.string,
size: PropTypes.oneOf(['small', 'medium', 'large']),
label: PropTypes.string.isRequired,
onClick: PropTypes.func,
};
Button.defaultProps = {
backgroundColor: null,
primary: false,
size: 'medium',
onClick: undefined,
};
src/stories/Button.stories.js
import React from 'react';
import { Button } from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
decorators: [(Story) => <div style={{ margin: '20px' }}><Story /></div>]
};
const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Button',
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Button',
};
to add decorators with the decorators
property.
It’s an array with functions we render the component with.
Story
is the component that we’re wrapping the component with.
It should be the button since we’re testing the button.
Stories for two or more components
If we have 2 or more components, then we put them under the same folder.
For example, we can write:
src/stories/ListItem.js
import React from 'react';
export const ListItem = ({ text }) => {
return (
<li>
{text}
</li>
);
};
src/stories/List.js
import React from 'react';
import PropTypes from 'prop-types';
export const List = ({ children, backgroundColor }) => {
return (
<ul style={{ backgroundColor }}>
{children}
</ul>
);
};
List.propTypes = {
backgroundColor: PropTypes.string
}
src/stories/List.stories.js
import React from 'react';
import { List } from './List';
import { ListItem } from './ListItem';
export default {
component: List,
title: 'List',
argTypes: {
backgroundColor: { control: 'color' },
},
};
export const Empty = (args) => <List {...args} />;
export const OneItem = (args) => (
<List {...args}>
<ListItem text='foo' />
</List>
);
export const ManyItems = (args) => (
<List {...args}>
<ListItem text='foo' />
<ListItem text='bar' />
<ListItem text='baz' />
</List>
);
We created the ListItem
and List
components that we used together in our story.
The List
component accepts the backgroundColor
prop and we set the argTypes
property to set the control for it to a color picker.
This way, we can set the color for it.
Conclusion
We can compose different components and test them together within one story with Storybook.