๐Ÿ“– Storybook

On this page

Stories Jump to heading

This is a good starter that includes most things youโ€™ll need when creating stories. This uses CS3.

// MyComponent.story.ts|tsx

import type { Meta, StoryObj } from '@storybook/react'

import { MyComponent } from './MyComponent'

const meta: Meta<typeof MyComponent> = {
/* ๐Ÿ‘‡ The title prop is optional.
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
* to learn how to generate automatic titles
*/

title: 'Path/To/MyComponent',
component: MyComponent,
}

export default meta
type Story = StoryObj<typeof MyComponent>

export const Basic: Story = {
args: {
prop1: 'Something',
prop2: true,
},
}

// https://storybook.js.org/docs/react/api/csf#spreadable-story-objects
export const BasicOnDark: Story = {
...Basic,
parameters: { background: { default: 'dark' } },
}

Custom render function Jump to heading

// This story uses a render function to fully control how the component renders.
export const Example: Story = {
render: () => (
<div style={{ maxWidth: '300px' }}>
<MyComponent prop1="Something" prop2={false} />
</div>
),
}

Play function Jump to heading

Storybookโ€™s play functions are small snippets of code executed when the story renders in the UI. They are convenient helper methods to help you test use cases that otherwise werenโ€™t possible or required user intervention.

// LoginForm.stories.ts|tsx

import type { Meta, StoryObj } from '@storybook/react'

import { within, userEvent } from '@storybook/testing-library'

import { expect } from '@storybook/jest'

import { LoginForm } from './LoginForm'

const meta: Meta<typeof LoginForm> = {
/* ๐Ÿ‘‡ The title prop is optional.
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
* to learn how to generate automatic titles
*/

title: 'Form',
component: LoginForm,
}

export default meta
type Story = StoryObj<typeof LoginForm>

export const EmptyForm: Story = {}

/*
* See https://storybook.js.org/docs/react/writing-stories/play-function#working-with-the-canvas
* to learn more about using the canvasElement to query the DOM
*/

export const FilledForm: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)

// ๐Ÿ‘‡ Simulate interactions with the component
await userEvent.type(canvas.getByTestId('email'), 'email@provider.com')

await userEvent.type(canvas.getByTestId('password'), 'a-random-password')

// See https://storybook.js.org/docs/react/essentials/actions#automatically-matching-args to learn how to setup logging in the Actions panel
await userEvent.click(canvas.getByRole('button'))

// ๐Ÿ‘‡ Assert DOM structure
await expect(
canvas.getByText(
'Everything is perfect. Your account is ready and we should probably get you started!'
)
).toBeInTheDocument()
},
}

Non-story exports Jump to heading

More info

// MyComponent.stories.ts|tsx

import type { Meta, StoryObj } from '@storybook/react'

import { MyComponent } from './MyComponent'

import someData from './data.json'

const meta: Meta<typeof MyComponent> = {
/* ๐Ÿ‘‡ The title prop is optional.
* See https://storybook.js.org/docs/react/configure/overview#configure-story-loading
* to learn how to generate automatic titles
*/

title: 'MyComponent',
component: MyComponent,
includeStories: ['SimpleStory'], // ๐Ÿ‘ˆ Storybook loads these stories
excludeStories: /.*Data$/, // ๐Ÿ‘ˆ Storybook ignores anything that contains Data
}

export default meta
type Story = StoryObj<typeof MyComponent>

export const simpleData = { foo: 1, bar: 'baz' }
export const complexData = { foo: 1, foobar: { bar: 'baz', baz: someData } }

export const SimpleStory: Story = {
args: {
data: simpleData,
},
}

CS2 format example Jump to heading

import React from 'react'
import { Story, Meta } from '@storybook/react/types-6-0'
import { MyComponent, MyComponentProps } from './myComponent'
// import docs from './myComponent.docs.mdx'

export default {
title: 'Components/MyComponent',
component: MyComponent,
parameters: {
// docs: { page: docs },
// paddings: [],
/* backgrounds: {
default: 'white',
},*/

},
/* argTypes: {
// Select element
variant: {
name: 'Variant',
defaultValue: 'large',
control: {
type: 'select',
options: ['large', 'small']
},
},
// Radio
variant: {
name: 'Variant',
defaultValue: 'large',
control: {
type: 'radio',
options: ['large', 'small']
},
},
}, */

} as Meta

const Template: Story<MyComponentProps> = (args) => <Zander {...args} />

export const Standard = Template.bind({})
Standard.args = {}

/* Standard.decorators = [
(Story) => (
<Box sx={{ color: 'bright' }}>
<Story />
</Box>
),
]*/

/* Standard.parameters = {
backgrounds: {
default: 'blue',
},
}*/

MDX Jump to heading

import { Meta, Story, Preview, Anchor } from โ€˜@storybook/addon-docs/blocksโ€™

โ€”

# Title

## Example code

jsx some code

Story inside MDX Jump to heading

<Preview>
<Story name="Example"></Story>
</Preview>

Config Jump to heading

Declarative Storybook configuration

// main.js
const path = require('path')
const SRC_PATH = path.join(__dirname, '../src')

module.exports = {
stories: [
'../docs/**/*.stories.mdx',
'../src/**/*.stories.mdx',
'../**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'storybook-addon-paddings',
'storybook-addon-color-mode',
'@storybook/addon-a11y',
],
typescript: {
check: false,
checkOptions: {},
reactDocgen: 'none',
},
}
// preview.js
import React from 'react'
import { withPaddings } from 'storybook-addon-paddings'
import { ThemeProvider } from 'theme-ui'
import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'
import theme from '../src/theme/index.js'

export const parameters = {
layout: 'fullscreen',
actions: { argTypesRegex: '^on[A-Z].*' },
// Set some different background colours
backgrounds: {
default: 'white',
values: [
{ name: 'white', value: '#fff' },
{ name: 'peach', value: 'hsla(36, 100%, 92%, 1)' },
{ name: 'pink', value: 'hsla(0, 69%, 91%, 1)' },
{ name: 'green', value: 'hsla(114, 70%, 93%, 1)' },
{ name: 'light blue', value: 'hsla(199, 100%, 93%, 1)' },
{ name: 'blue', value: 'hsl(240, 100%, 22%)' },
{ name: 'dark', value: 'hsl(109, 0%, 16%)' },
],
},
viewport: {
viewports: {
// A few custom viewports
iphoneSe: {
name: 'iPhone SE',
styles: {
height: '667px',
width: '375px',
},
type: 'mobile',
},
iphone12Mini: {
name: 'iPhone 12 Mini',
styles: {
height: '812px',
width: '375px',
},
type: 'mobile',
},
// the default viewports from Storybook
...INITIAL_VIEWPORTS,
},

// storybook-addon-paddings
paddings: [
{ name: 'Small', value: '16px' },
{ name: 'Medium', value: '32px', default: true },
{ name: 'Large', value: '64px' },
],

// storybook-addon-color-mode
colorMode: {
defaultMode: 'default',
modes: {
light: {
name: 'Light',
},
},
},
},
options: {
// custom sidebar sorting
storySort: {
order: [
'Introduction',
['Welcome', 'Getting Started'],
'Docs',
'Advanced',
'Typography',
'Layout',
'Design System',
'Page sections',
'Atoms',
'Components',
],
},
},
}

export const decorators = [
withPaddings,
(Story) => (
<ThemeProvider theme={theme}>
<Story />
</ThemeProvider>
),
]

Useful addons Jump to heading

yarn add --dev @storybook/preset-typescript @storybook/addon-docs/preset @storybook/addon-links/register @storybook/addon-actions/register @storybook/addon-backgrounds/register @storybook/addon-a11y/register @storybook/addon-knobs/register @storybook/addon-viewport/register storybook-addon-color-mode/register storybook-addon-paddings story-description-loader

With Gatsby: https://www.gatsbyjs.org/docs/visual-testing-with-storybook/


← Back home