
Component Story Format 3 is here
Next gen story format to make you more productive

Stories visualize how a component behaves in different scenarios. Component Story Format (CSF) is the universal file format for stories.
Component Story Format 3 marks an evolution in stories that trims boilerplate code and improves ergonomics. This makes stories more concise and faster to write.
I'm excited to announce the full release of CSF3. During the 18 month beta period, the community helped us find issues and refine the format. Starting with Storybook 7, CSF3 will be the default way to write stories.
Improvements include:
- β»οΈ Spreadable story objects to easily extend stories
- π Default render functions for brevity
- π Automatic titles for convenience
- βΆοΈ Play functions for scripted interactions and tests
- β 100% backwards compatible with CSF 2
Read on to learn more about the format, whatβs changed since the original announcement, and how to make the most of it in Storybook 7.
Wait, but why?
Developing UI components outside of your application is the best way to create high-quality components. Storybook pioneered this style of Component-driven Development (CDD).
Stories are now used for visual review by designers and product managers, as well as for design system documentation, automated testing, and even generating design assets from production components.
It's no surprise that Storybook is used to build many of the world's most popular UIs at Shopify, IBM, and Salesforce.
CSF3 is the next evolution of storiesβeasier to write and maintain
Much like its predecessor, CSF3 is based on ESM. The default export contains information about the component, and one or more named exportsβstoriesβcapture different component states. The main difference is that stories are now objects, and you can attach a play function to each story to simulate user interactions.
CSF3 is fully backwards compatible with CSF2, which is still supported in Storybook 7. Weβve even back ported play functions to CSF2.
We recommend migrating because CSF3 is more expressive and maintainable with less boilerplate code required from you. In most cases, you can automatically migrate from CSF 2 to 3 using a codemod.

CSF3 feature recap
Large projects can consist of hundreds of components and thousands of stories. When you write this many stories, ergonomic improvements result in noticeable quality of life improvements. Our goal was to streamline the story format to make writing, reading, and maintaining stories easier.
Let's see what CSF3 looks like in a hypothetical RegistrationForm
component.
The default export declares the component that youβre writing stories for:
// RegistrationForm.stories.js
import { RegistrationForm } from './forms/RegistrationForm';
export default {
title: 'forms/RegistrationForm',
component: RegistrationForm,
};
And stories are now objects:
export const EmptyForm = {
render: (args) => <RegistrationForm {...args} />,
args: { /* ... */ },
parameters: { /* ... */ },
};
Default render functions for brevity. 90% of the time, writing a story is just passing some inputs to your component in a standard way.
In CSF3, if you donβt specify the render function, each story renders the component and passes in all arguments. This greatly simplifies your code.
In our RegistrationForm
example, the render function is boilerplate:
export const EmptyForm = {
// render: (args) => <RegistrationForm {...args} />, -- now optional!
args: { /* ... */ },
parameters: { /* ... */ },
};
Spreadable story objects for reuse. When youβre trying to model complex states, itβs useful to be able to extend existing stories instead of writing them anew. Suppose you want to show the filled form, but in a different viewport:
export const FilledForm = {
args: {
email: 'marcus@acme.com',
password: 'j1287asbj2yi394jd',
}
};
export const FilledFormMobile = {
...FilledForm,
parameters: {
viewports: { default: 'mobile' }
},
};
Play functions for scripted interactions. Some UI states are impossible to capture without user interaction. The play function runs after the story has been rendered, and uses testing-library
to simulate user interactions. For example:
// RegistrationForm.stories.ts|tsx
import { userEvent, within } from '@storybook/testing-library';
// ...
export const FilledForm = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const emailInput = canvas.getByLabelText('email', {
selector: 'input'
});
await userEvent.type(emailInput, 'example-email@email.com', {
delay: 100
});
const passwordInput = canvas.getByLabelText('password', {
selector: 'input'
});
await userEvent.type(passwordInput, 'ExamplePassword', {
delay: 100
});
const submitButton = canvas.getByRole('button');
await userEvent.click(submitButton);
},
};

Automatic titles for convenience. In CSF, a storyβs title determines where it shows up in the navigation hierarchy in the UI. In CSF3, the title can be automatically generated based on the fileβs location relative to the root. Less to type, and nothing to update if you reorder your files.
export default {
// title: 'forms/RegistrationForm' -- optional
component: RegistrationForm,
};

For an in-depth description of CSF3βs features and rationale, and exactly how it differs from CSF2, please see the original CSF3 post.
Changes to the original
Over the past year and half, users have been testing CSF3 in their projects. Based on feedback weβve made a few changes from the original.
Better TypeScript types. Weβve updated the Meta/Story types in 7.0 to support type safety and autocompletion for stories. Stay tuned for a dedicated post about this in the coming weeks.
Updated autotitle heuristics. Autotitle generates the βtitleβ (path in the Storybook sidebar) based on a CSF fileβs disk location. For example, if /project/path/src
is the story root, /project/path/src/atoms/Button.stories.js
would get the title atoms/Button
. However, the naive heuristic doesnβt handle common patterns like atoms/Button/Button.stories.js
or atoms/Button/index.stories.js
. We updated the heuristics to account for this. For full migration instructions and several other autotitle improvements including better prefix handling and capitalization, see MIGRATION.md.
Upgraded documentation and CLI templates. Last but not least, weβve upgraded the official documentation for 7.0 with CSF3 source snippets. Weβve also updated the CLI to generate CSF3 for new projects.
Upgrade to CSF3 today
CSF3 is fully backwards compatible, so your existing CSF stories still work fine without modification. We wonβt deprecate the old format any time soon. However, CSF3 is a big step forward, and we recommend upgrading your stories as part of upgrading to Storybook 7.0 (SB7).
To upgrade to SB7, see our SB7 migration guide. After your project is upgraded, you can optionally migrate your CSF stories to CSF3 using the following codemod. Be sure to update the glob to include the files you want to update.
npx storybook@next migrate csf-2-to-3 --glob="**/*.stories.js"

If you cannot use the codemod, we also have upgrade instructions available.
Get involved
Component Story Format (CSF) helps you develop, test, and document your components in isolation. With CSF3 comes improved ergonomics to help you write more stories with less effort.
CSF3 was developed by Michael Shilman (me!), Kasper Peulen, Tom Coleman, and Pavan Sunkara with testing and feedback from the entire Storybook community.
Storybook is the product of over 1600 community committers. Join us on GitHub or chat with us on Discord. Finally, follow @storybookjs on Twitter for the latest news.
Component Story Format 3 is here!
— Storybook (@storybookjs) January 26, 2023
β»οΈ Spreadable story objects
π Default render functions
π Automatic titles
β―οΈ Play functions to script interactions
β 100% backwards compatible with CSF 2
ποΈΒ Read all about it... pic.twitter.com/TaMIKrTNV9