Writing CSF3 Stories
Export a default meta object and named stories using the Component Story Format 3.
Writing CSF3 Stories is a free React Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
What Is CSF3?
Component Story Format 3 (CSF3) is the current Storybook story format. Stories are plain JavaScript/TypeScript objects — no render function needed for simple cases.
The Meta Export
Every story file must have a default export — the Meta object — that describes the component and sets shared story configuration.
import type { Meta } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'UI/Button', // Storybook sidebar path
component: Button,
tags: ['autodocs'], // enables auto-generated docs page
};
export default meta;Named Story Exports
Each named export from the file is a story. In CSF3, a story is an object with an args property (the component's props).
import type { StoryObj } from '@storybook/react';
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: { label: 'Click me', variant: 'primary' },
};
export const Secondary: Story = {
args: { label: 'Cancel', variant: 'secondary' },
};
export const Disabled: Story = {
args: { label: 'Unavailable', disabled: true },
};Story Inheritance
Stories inherit args from the meta object. Set shared defaults in meta.args and override per-story as needed.
const meta: Meta<typeof Button> = {
component: Button,
args: {
onClick: fn(), // from @storybook/test
disabled: false,
},
};
export const Large: Story = {
args: { size: 'large', label: 'Large Button' }, // merges with meta args
};Render Function Override
Provide a render function in a story for complex cases that need custom JSX wrapping or multiple instances.
export const WithIcon: Story = {
render: (args) => (
<div style={{ display: 'flex', gap: 8 }}>
<Button {...args} icon={<StarIcon />} />
<Button {...args} icon={<HeartIcon />} />
</div>
),
args: { label: 'Action' },
};Decorators on Individual Stories
Add a decorators array to a story to wrap it in additional providers or layout for that specific story only.
export const InsideCard: Story = {
decorators: [
(Story) => (
<div style={{ padding: 24, background: '#f5f5f5' }}>
<Story />
</div>
),
],
args: { label: 'Card Button' },
};Parameters on Stories
Use parameters to configure addons per story — like setting the background or viewport for a specific state.
export const DarkMode: Story = {
parameters: {
backgrounds: { default: 'dark' },
},
args: { label: 'Dark Button', variant: 'primary' },
};The autodocs Tag
Adding tags: ['autodocs'] to the meta generates an automatic documentation page with a prop table and live examples from all named stories.
Story for Each State
Write a story for every meaningful component state: empty, loading, error, single item, many items, RTL layout, etc.
export const Loading: Story = { args: { isLoading: true } };
export const Error: Story = { args: { error: 'Failed to load' } };
export const Empty: Story = { args: { items: [] } };
export const WithData: Story = { args: { items: mockUsers } };Naming Conventions
Use PascalCase story names that describe the state. Avoid generic names like Default — be specific: PrimaryDisabled, SecondaryWithIcon.
Grouping Stories with title
The title in meta uses slash notation to create nested groups in the Storybook sidebar: 'Forms/Input' creates a Forms group with an Input subgroup.
const meta: Meta<typeof TextInput> = {
title: 'Forms/TextInput',
component: TextInput,
};
// Sidebar: Forms → TextInput → Primary, Error, Disabled...Reusing Stories in Tests
CSF3 stories are plain objects, so you can import and compose them in unit tests or other stories.
import { Primary } from './Button.stories';
test('renders primary button', () => {
render(<Button {...Primary.args} />);
expect(screen.getByText('Click me')).toBeInTheDocument();
});Quick Check
In CSF3, how do you define a story's props/state?
Recap
CSF3 stories are typed objects with args. Set shared defaults in meta.args, override per story, use render for custom JSX, and add tags: ['autodocs'] for auto-generated documentation. Write a story for every meaningful component state.
Frequently asked questions
Is the “Writing CSF3 Stories” lesson free?
Yes — the full text of “Writing CSF3 Stories” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.
What will I learn in “Writing CSF3 Stories”?
Export a default meta object and named stories using the Component Story Format 3. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start React Academy?
No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Writing CSF3 Stories” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this React Academy lesson?
Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.