storybook-patterns
Storybook patterns: CSF3 (meta satisfies Meta, play functions, @storybook/test), addon ecosystem (a11y, interactions, docs), MSW integration for API mocking, Chromatic CI, storybook-test-runner for Jest/Playwright execution, and Storybook as living documentation.
Best use case
storybook-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Storybook patterns: CSF3 (meta satisfies Meta, play functions, @storybook/test), addon ecosystem (a11y, interactions, docs), MSW integration for API mocking, Chromatic CI, storybook-test-runner for Jest/Playwright execution, and Storybook as living documentation.
Teams using storybook-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/storybook-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How storybook-patterns Compares
| Feature / Agent | storybook-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Storybook patterns: CSF3 (meta satisfies Meta, play functions, @storybook/test), addon ecosystem (a11y, interactions, docs), MSW integration for API mocking, Chromatic CI, storybook-test-runner for Jest/Playwright execution, and Storybook as living documentation.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Storybook Patterns
Component development environment and living documentation system.
## When to Activate
- Writing stories for a new component (CSF3 format)
- Setting up interaction tests with `play` functions
- Configuring MSW for API mocking in stories
- Setting up Chromatic for visual regression
- Auditing existing Storybook setup
- Building automated accessibility checks into stories
- Migrating legacy CSF2 stories to CSF3 with `satisfies Meta` for full type safety
- Running stories as automated tests in CI using `@storybook/test-runner` and axe-playwright
---
## Component Story Format 3 (CSF3)
The current standard — no default exports, `satisfies` for type safety.
### Basic Story
```typescript
// components/Button/Button.stories.ts
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
},
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'danger'],
description: 'Visual variant of the button',
},
onClick: { action: 'clicked' },
},
tags: ['autodocs'], // Generates automatic Docs page
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
// Each named export is a story
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Click me',
},
};
export const Disabled: Story = {
args: {
variant: 'primary',
children: 'Disabled',
disabled: true,
},
};
export const Loading: Story = {
args: {
children: 'Loading...',
loading: true,
},
};
```
### Play Functions (Interaction Tests)
```typescript
import { within, userEvent, expect } from '@storybook/test';
import type { Meta, StoryObj } from '@storybook/react';
import { LoginForm } from './LoginForm';
const meta = {
component: LoginForm,
tags: ['autodocs'],
} satisfies Meta<typeof LoginForm>;
export default meta;
type Story = StoryObj<typeof meta>;
export const SuccessfulLogin: Story = {
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await step('Fill in credentials', async () => {
await userEvent.type(
canvas.getByLabelText('Email'),
'user@example.com',
{ delay: 50 }
);
await userEvent.type(
canvas.getByLabelText('Password'),
'password123',
{ delay: 50 }
);
});
await step('Submit the form', async () => {
await userEvent.click(canvas.getByRole('button', { name: 'Sign in' }));
});
await step('Verify success state', async () => {
await expect(
canvas.getByText('Welcome back!')
).toBeInTheDocument();
});
},
};
export const ValidationErrors: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Submit empty form
await userEvent.click(canvas.getByRole('button', { name: 'Sign in' }));
// Should show validation errors
await expect(canvas.getByText('Email is required')).toBeVisible();
await expect(canvas.getByText('Password is required')).toBeVisible();
},
};
```
---
## Addons
### `@storybook/addon-a11y` — Accessibility
```bash
npm install --save-dev @storybook/addon-a11y
```
```typescript
// .storybook/main.ts
const config = {
addons: [
'@storybook/addon-a11y',
// ...
],
};
```
```typescript
// Disable a11y check for specific story (with reason)
export const DecorativeIcon: Story = {
parameters: {
a11y: {
// Icon is decorative — not exposed to screen readers
disable: true,
},
// Or configure rules:
a11y: {
config: {
rules: [{ id: 'color-contrast', enabled: false }],
},
},
},
};
```
### `@storybook/addon-interactions` — Visual Interaction Tests
```bash
npm install --save-dev @storybook/addon-interactions @storybook/test
```
Interaction tests run in the Storybook UI with step-by-step playback:
- "Step 1: Fill email" → show state
- "Step 2: Submit" → show state
- "Step 3: Verify success" → pass/fail
### `@storybook/test-runner` — Run Stories as Tests
```bash
npm install --save-dev @storybook/test-runner
```
```json
// package.json
{
"scripts": {
"test-storybook": "test-storybook"
}
}
```
```typescript
// .storybook/test-runner.ts
import type { TestRunnerConfig } from '@storybook/test-runner';
import { checkA11y, injectAxe } from 'axe-playwright';
const config: TestRunnerConfig = {
async preVisit(page) {
await injectAxe(page);
},
async postVisit(page) {
await checkA11y(page, '#storybook-root', {
detailedReport: true,
detailedReportOptions: { html: true },
});
},
};
export default config;
```
```bash
# Run all stories as tests
npm run build-storybook -- --quiet
npx http-server storybook-static --port 6006 &
npm run test-storybook
```
---
## MSW Integration (Mock Service Worker)
Mock API calls in stories without changing implementation code.
```bash
npm install msw msw-storybook-addon --save-dev
npx msw init public/ --save # Install service worker
```
```typescript
// .storybook/preview.ts
import { initialize, mswLoader } from 'msw-storybook-addon';
initialize(); // Start MSW
export default {
loaders: [mswLoader],
};
```
```typescript
// ProductPage.stories.ts
import { http, HttpResponse } from 'msw';
export const WithData: Story = {
parameters: {
msw: {
handlers: [
http.get('/api/products', () => {
return HttpResponse.json([
{ id: 1, name: 'Widget Pro', price: 49.99 },
{ id: 2, name: 'Widget Lite', price: 9.99 },
]);
}),
],
},
},
};
export const Empty: Story = {
parameters: {
msw: {
handlers: [
http.get('/api/products', () => HttpResponse.json([])),
],
},
},
};
export const Error: Story = {
parameters: {
msw: {
handlers: [
http.get('/api/products', () =>
HttpResponse.json({ error: 'Service unavailable' }, { status: 503 })
),
],
},
},
};
```
---
## Chromatic CI Integration
```yaml
# .github/workflows/chromatic.yml
name: Chromatic
on:
push:
branches: [main]
pull_request:
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for Chromatic baselines
- uses: actions/setup-node@v4
with: { node-version: 20, cache: npm }
- run: npm ci
- name: Publish to Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
onlyChanged: true # Only test affected stories
exitZeroOnChanges: false # Fail on unreviewed changes
autoAcceptChanges: main # Auto-accept changes on main
```
```bash
# Local: push to Chromatic
npx chromatic --project-token=<token>
# Build only changed stories (faster in CI)
npx chromatic --project-token=<token> --only-changed
# Force rebuild all (e.g., after dependency update)
npx chromatic --project-token=<token> --force-rebuild
```
---
## Storybook as Living Documentation
### autodocs
```typescript
// Enable globally for all components
// .storybook/preview.ts
export const parameters = {
docs: {
autodocs: 'tag', // Only for stories with tags: ['autodocs']
},
};
// Or per story:
const meta = {
tags: ['autodocs'], // Generates Docs page from JSDoc + stories
} satisfies Meta<typeof Component>;
```
### ArgTypes Documentation
```typescript
const meta = {
component: DatePicker,
argTypes: {
value: {
description: 'Currently selected date',
control: 'date',
table: {
type: { summary: 'Date | null' },
defaultValue: { summary: 'null' },
},
},
onChange: {
description: 'Called when user selects a date',
action: 'date-changed',
table: { type: { summary: '(date: Date) => void' } },
},
locale: {
description: 'BCP 47 language tag for date formatting',
control: 'text',
table: {
type: { summary: 'string' },
defaultValue: { summary: '"en-US"' },
},
},
},
} satisfies Meta<typeof DatePicker>;
```
### Story Descriptions
```typescript
export const WithCustomLocale: Story = {
name: 'Localized (German)',
parameters: {
docs: {
description: {
story: 'Date picker configured for German locale — uses DD.MM.YYYY format and German month names.',
},
},
},
args: {
locale: 'de-DE',
},
};
```
---
## .storybook/main.ts Configuration
```typescript
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-essentials', // Controls, Actions, Docs, Viewport
'@storybook/addon-a11y', // Accessibility checks
'@storybook/addon-interactions', // Interaction test debugging
'msw-storybook-addon', // API mocking
'@chromatic-com/storybook', // Chromatic integration
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
typescript: {
check: true,
},
};
export default config;
```
---
## CSF2 → CSF3 Migration
```typescript
// CSF2 (old — still works but less type-safe)
export default {
title: 'Components/Button',
component: Button,
};
export const Primary = (args) => <Button {...args} />;
Primary.args = { variant: 'primary', children: 'Click me' };
// CSF3 (new — fully typed, no template function needed)
import type { Meta, StoryObj } from '@storybook/react';
const meta = { component: Button } satisfies Meta<typeof Button>;
export default meta;
export const Primary: StoryObj<typeof meta> = {
args: { variant: 'primary', children: 'Click me' },
};
```
## Reference
- `visual-testing` — Chromatic setup, Playwright screenshots, baseline management
- `e2e-testing` — Playwright functional tests (not visual)
- `accessibility` — WCAG guidelines the a11y addon checks againstRelated Skills
zero-trust-patterns
Zero-Trust security patterns — mTLS between microservices (Istio/SPIFFE), SPIRE workload identity, OPA/Envoy authorization, NetworkPolicy default-deny-all, short-lived credentials, service mesh security, and Kubernetes RBAC hardening.
webrtc-patterns
WebRTC patterns — peer connection setup, ICE/STUN/TURN configuration, signaling server design, SFU vs mesh topology, screen sharing, media track management, and reconnect/ICE restart handling.
webhook-patterns
Webhook patterns for receiving, verifying (HMAC), and idempotently processing third-party events. Covers Stripe, GitHub, and generic webhook patterns, delivery guarantees, retry handling, and testing.
wasm-patterns
WebAssembly patterns: wasm-pack, wasm-bindgen (JS↔Wasm interop), WASI, Component Model, wasm-opt, Rust-to-WASM compilation, JS integration (web workers, streaming instantiation), and production deployment (CDN, Content-Type headers).
ux-micro-patterns
UX micro-patterns for every product state: Empty States, Loading States (skeleton screens, spinners, optimistic UI), Error States, Success States, Confirmation Dialogs, Onboarding Flows, and Progressive Disclosure. These patterns apply to every feature — done wrong, they're the biggest source of user confusion.
typescript-patterns
TypeScript patterns — type system best practices, strict mode, utility types, generics, discriminated unions, error handling with Result types, and module organization. Core patterns for production TypeScript.
typescript-patterns-advanced
Advanced TypeScript — mapped types, template literal types, conditional types, infer, type guards, decorators, async patterns, testing with Vitest/Jest, and performance. Extends typescript-patterns.
typescript-monorepo-patterns
TypeScript monorepo patterns with Turborepo + pnpm workspaces. Covers package structure, shared configs, task pipeline caching, build orchestration, and publishing strategy.
terraform-patterns
Infrastructure as Code with Terraform — project structure, remote state, modules, workspace strategy, AWS/GCP patterns, CI/CD integration, and security hardening. The standard for managing production infrastructure.
swiftui-patterns
SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.
swift-patterns
Core Swift patterns — value vs reference types, protocols, generics, optionals, Result, error handling, Codable, and module organization. Foundation for all Swift development.
swift-patterns-advanced
Advanced Swift patterns — property wrappers, result builders, Combine basics, opaque & existential types, macro system, advanced generics, and performance optimization. Extends swift-patterns.