Addons & Tooling
| Field | Value |
|---|---|
| Type | Agent Reference |
| Source | ~/.copilot/agents/_refs/storybook-designer/addons-and-tooling.md |
| Description | Not specified |
Source Content
Addons & Tooling
Addon Stack
| Addon | Package | Purpose |
|---|---|---|
| A11y | @storybook/addon-a11y | axe-powered accessibility panel; runs in CI |
| Interactions | @storybook/test | play functions, userEvent, expect, within |
| Controls | built-in | Auto-generated from TypeScript props |
| Viewport | built-in | Mobile/tablet/desktop preview switching |
| Backgrounds | built-in | Light, dark, custom tonal backgrounds |
| Docs | built-in | Auto-generated docs from CSF3 + createComponentDocs |
| MSW | msw-storybook-addon | API mocking in stories (requires msw setup) |
Accessibility Addon
Every story should pass the a11y addon panel before shipping. The panel runs axe-core automatically.
Configuring a11y per story:
export const Default: Story = { parameters: { a11y: { // Disable a specific rule only when there is a documented reason config: { rules: [ { id: 'color-contrast', // Only disable in a story that intentionally shows a disabled state enabled: false, }, ], }, }, },}Never globally disable a11y rules. Story-level overrides require a comment explaining why.
Interactions Addon Setup
Install: @storybook/test (bundled with Storybook 8, no separate install needed).
The test runner (@storybook/test-runner) runs all play functions in CI headlessly:
# Run interaction testspnpm test # runs via the configured test script# OR directly:npx storybook test --url http://localhost:6006Configure in package.json:
{ "scripts": { "test-storybook": "storybook test --url http://localhost:6006" }}MSW Addon for API Mocking
Use msw-storybook-addon to mock API calls in stories that need server data:
import { initialize, mswLoader } from 'msw-storybook-addon'
initialize()
const preview = { loaders: [mswLoader],}
export default preview// In a storyimport { http, HttpResponse } from 'msw'
export const WithData: Story = { parameters: { msw: { handlers: [ http.get('/api/users', () => { return HttpResponse.json([ { id: '1', name: 'Sarah Okafor', email: 'sarah@example.com', role: 'admin' }, ]) }), ], }, },}
export const ErrorState: Story = { parameters: { msw: { handlers: [ http.get('/api/users', () => { return HttpResponse.error() }), ], }, },}Preview Decorators
Wrap stories in necessary providers via .storybook/preview.tsx decorators — not in individual story files:
import type { Preview } from '@storybook/react-vite'import { QueryClient, QueryClientProvider } from '@tanstack/react-query'import { ThemeProvider } from '../src/components/theme-provider'
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false, staleTime: 0 } },})
const preview: Preview = { decorators: [ (Story) => ( <QueryClientProvider client={queryClient}> <ThemeProvider defaultTheme="light"> <Story /> </ThemeProvider> </QueryClientProvider> ), ], parameters: { backgrounds: { default: 'light', values: [ { name: 'light', value: 'hsl(44 35% 96%)' }, // --brand-mist light { name: 'dark', value: 'hsl(217 22% 18%)' }, // --brand-mist dark { name: 'white', value: '#ffffff' }, ], }, viewport: { viewports: { mobile: { name: 'Mobile', styles: { width: '390px', height: '844px' } }, tablet: { name: 'Tablet', styles: { width: '768px', height: '1024px' } }, desktop: { name: 'Desktop', styles: { width: '1440px', height: '900px' } }, }, }, },}
export default previewDark Mode in Stories
For components with dark mode support, add a dark mode story using the backgrounds parameter:
export const DarkMode: Story = { parameters: { backgrounds: { default: 'dark' }, // Apply the night theme data attribute theme: 'night', }, decorators: [ (Story) => ( <div data-theme="night"> <Story /> </div> ), ],}Icon Controls
Use the shared icon picker helpers — never write per-story option lists:
import { iconControl, iconArgType } from '@/lib/storybook-icon-controls'
const meta = { component: Button, argTypes: { leadingIcon: iconArgType, // gives a searchable icon picker in Controls trailingIcon: iconArgType, },} satisfies Meta<typeof Button>
export const WithIcon: Story = { args: { leadingIcon: iconControl('Plus'), children: 'Add item', },}createComponentDocs
All fields:
createComponentDocs({ summary: string, // required — one sentence when: string, // required — when to use this component whenNot: string, // required — when NOT to use it (name alternatives) motion?: string, // describe animation when present reducedMotion?: string, // describe reduced-motion behavior a11y?: string, // notable accessibility behavior status?: 'stable' | 'experimental' | 'deprecated',})Storybook Configuration Files
.storybook/ main.ts ← addon list, framework, staticDirs, features preview.tsx ← global decorators, parameters, loaders manager.ts ← sidebar theme, panel position (rarely needed)main.ts essentials:
import type { StorybookConfig } from '@storybook/react-vite'
const config: StorybookConfig = { stories: ['../src/**/*.stories.@(ts|tsx|mdx)'], addons: [ '@storybook/addon-a11y', '@storybook/addon-interactions', '@storybook/addon-docs', 'msw-storybook-addon', ], framework: { name: '@storybook/react-vite', options: {}, }, staticDirs: ['../public'], features: { // Storybook 8 features },}
export default config