Storybook is a set of libraries that lets us create components and preview them by passing in various attributes to them. The recent release of Storybook 6 included many convenient new features. Without further ado, let’s take a look at the new features and how to use them.
With Storybook 6, we can build a Storybook with ease: all we have to do is run npx sb init
on our project and we have Storybook added.
If we wanted to add Storybook to a React project created with create-react-app, for example, we’d just use that command. Do note, however, that npx sb init
only works with existing projects and can’t be used on an empty project folder.
So, to use Storybook with a React project, we first run:
npx create-react-app storybook-project
This creates the storybook-project
React project. Then, we go to the storybook-project
folder and run npx sb init
to add Storybook to it.
To upgrade an existing Storybook project to the latest version, we run npx sb upgrade
to install it. We’d then run yarn add @storybook/addon-essentials --dev
to install the addons, which render the content we see below the preview of the component.
The Storybook Essentials package has a few useful addons for changing the viewport in which we can preview our component. It also has an addon that allows us to document our component using either JSX or MDX code. (MDX is a mix of Markdown and JSX.)
Other addons include:
TypeScript support is also built-in with Storybook 6, so we can immediately use TypeScript out of the box without extra configuration.
In Storybook, args are attributes that we pass into our components to change it. This lets us make preset configurations for our component so that we can preview them.
We can set the args in the story files. For example, if we have a React Storybook project, we can create our components and stories as follows:
//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.css .button { font-weight: 700; border: 0; border-radius: 3em; cursor: pointer; display: inline-block; line-height: 1; } .button-primary { color: white; background-color: #1ea7fd; } .button-secondary { color: #333; background-color: transparent; } .button-small { font-size: 12px; padding: 10px; } .button-medium { font-size: 14px; padding: 11px; } .button-large { font-size: 16px; padding: 12px; }
//src/stories/Button.stories.js import React from 'react'; import { Button } from './Button'; export default { title: 'Example/Button', component: Button, argTypes: { backgroundColor: { control: 'color' }, }, }; 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', };
The Button.js
file has the component file, and the button.css
has the styles for the Button
component.
The Button
components takes several props:
primary
prop lets us set the class for to style the button in various waysbackgroundColor
set the background colorsize
sets the sizelabel
sets the button textThe rest of the props are passed into the button
element.
Below that, we add some prop type validations so that we can set our args properly and let Storybook pick the controls for the args. primary
is a Boolean, so it’ll be displayed as a checkbox button. backgroundColor
is a string.
size
can be one of three values, so Storybook will create a dropdown for it automatically to let us select the value. label
is a string prop, so it’ll show as a text input. The input controls are in the Controls tab of the Storybook screen below the component preview.
The args are set in the Button.stories.js
file, which is a file with the stories. Storybook will pick up any file that ends with stories.js
or stories.ts
as a story files.
The argTypes
property lets us set the control for our args. In our example, we set the backgroundColor
prop to be controlled with the 'color'
control, which is the color picker.
Below that, we have our stories code. We create a template from the Button
component with our Template
function. It takes the args we pass in and passes them all off to the Button
.
Then, we call Template.bind
to let us pass the args as props to Button
by setting the args
property to an object with the props.
Template.bind
returns a story object, which we can configure with args. This is a convenient way to set the props that we want to preview in our story.
The Controls tab has all the form controls that we can use to set our component’s props. Storybook picks up the props and displays the controls according to the prop type.
Also, we can set the form control type as we wish in the stories file, as we’ve seen in the argTypes
property in the previous sections’ example. With this, we can set the props live in the Storybook screen and see what the output looks like in the Canvas tab.
The backgroundColor
prop’s value is changed with a color picker. The primary
prop is changed with a toggle button that lets us set it to true
or false
. And the size
prop is controlled with a dropdown since it can only be one of three values.
Storybook does the work automatically unless we change the control types ourselves. This is a very useful feature that lets us change our component without changing any code.
Storybook 6 introduces the ability to combine multiple Storybook projects by referencing different Storybook projects in another project.
We can do this by adding the following code in the .storybook/main.js
file:
module.exports = { //... refs: { react: { title: "React", url: 'http://localhost:6007' }, angular: { title: "Angular", url: 'http://localhost:6008' } } }
This lets us load multiple Storybook projects’ stories in one project. Now, if we run npm run storybook
, we’ll see all the Storybook stories displayed from both projects on the left sidebar.
The title
value is displayed in the left sidebar, and the url
has the URL to reach the Storybook project.
Storybook 6 comes with many useful new features. Storybook setup in existing projects can now be done with one command if you have a project that Storybook supports. We can use args to preset props in stories and preview them easily, and we can reference another Storybook project from another with minimal configuration.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowCompare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.