CSF — Component Story Format
Modern Storybook describes stories as ordinary ES modules: meta + named exports. That is easy to type, review in PRs, and generate docs from.
Button.stories.jsx skeleton
import { Button } from './Button';
export default {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'outline', 'ghost', 'destructive'],
},
size: { control: 'inline-radio', options: ['sm', 'md', 'lg'] },
disabled: { control: 'boolean' },
onClick: { action: 'clicked' },
},
args: {
children: 'Save',
variant: 'primary',
size: 'md',
},
};
export const Primary = {};
export const Secondary = {
args: { variant: 'secondary' },
};
export const Loading = {
args: { loading: true, children: 'Saving…' },
};
export const WithClick = {
args: { onClick: () => {} },
};
Primary = {} inherits args from meta — less duplication.
Controls
Controls let you tweak props without editing code. Configure argTypes:
select/radiofor enum variants;booleanfor flags;textfor children (careful with ReactNode);- disable what is unsafe to tweak (
control: falsefor a complexicon).
Actions
The Actions addon logs callbacks (onClick, onOpenChange). In argTypes set action: 'clicked', or use fn() from storybook/test in SB8 — so the Actions panel shows interaction.
Decorators
Wrappers for context:
export default {
component: Modal,
decorators: [
(Story) => (
<div style={{ minHeight: 320 }}>
<Story />
</div>
),
],
};
For themes — a global decorator in preview with data-theme on documentElement.
State matrices
For a DS, “gallery” stories are useful:
export const AllVariants = {
render: () => (
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
</div>
),
parameters: { controls: { disable: true } },
};
Those pages catch visual regressions across a whole variant family at once.
Naming
title:Components/Button,Forms/Input,Feedback/Badge.- Export names:
Primary,Disabled,WithError— no “Test…” verbs. - One story — one clear scenario; do not mix loading and destructive without a reason.
Practice
Write CSF for Button and Input: default args, 4–6 states, actions on events, a variants matrix. Open Controls and confirm the enums match the component API.