$npx -y skills add dylantarre/design-system-skills --skill storybookDocuments components with Storybook using CSF 3.0, controls, and MDX. Use when creating component catalogs, interactive examples, visual testing setups, or design system documentation sites.
| 1 | # Storybook Component Documentation |
| 2 | |
| 3 | ## Overview |
| 4 | |
| 5 | Document and showcase design system components using Storybook. Create interactive examples, visual tests, and comprehensive documentation with controls, args, and MDX. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Setting up component documentation |
| 10 | - Creating interactive component playground |
| 11 | - Visual regression testing |
| 12 | - Building a component library catalog |
| 13 | - Onboarding developers to the design system |
| 14 | |
| 15 | ## Quick Reference: Story Formats |
| 16 | |
| 17 | | Format | Use Case | File Extension | |
| 18 | |--------|----------|----------------| |
| 19 | | CSF 3.0 | Standard stories with args | `.stories.tsx` | |
| 20 | | MDX | Documentation + stories | `.mdx` | |
| 21 | | Autodocs | Auto-generated docs | Enabled in config | |
| 22 | |
| 23 | ## The Process |
| 24 | |
| 25 | 1. **Install Storybook**: `npx storybook@latest init` |
| 26 | 2. **Configure for framework**: React, Vue, Svelte, Angular |
| 27 | 3. **Set up design tokens**: Import CSS tokens globally |
| 28 | 4. **Write stories**: One story per component variant |
| 29 | 5. **Add controls**: Enable props manipulation |
| 30 | 6. **Write docs**: MDX documentation pages |
| 31 | 7. **Add addons**: A11y, viewport, themes |
| 32 | |
| 33 | ## Project Structure |
| 34 | |
| 35 | ``` |
| 36 | .storybook/ |
| 37 | ├── main.ts # Storybook config |
| 38 | ├── preview.ts # Global decorators, parameters |
| 39 | ├── preview-head.html # Global CSS imports |
| 40 | └── theme.ts # Custom Storybook theme |
| 41 | |
| 42 | src/ |
| 43 | ├── components/ |
| 44 | │ ├── Button/ |
| 45 | │ │ ├── Button.tsx |
| 46 | │ │ ├── Button.stories.tsx |
| 47 | │ │ └── Button.mdx # Optional MDX docs |
| 48 | │ └── Input/ |
| 49 | ├── tokens/ |
| 50 | │ └── index.css |
| 51 | └── docs/ |
| 52 | ├── Introduction.mdx |
| 53 | ├── Colors.mdx |
| 54 | └── Typography.mdx |
| 55 | ``` |
| 56 | |
| 57 | --- |
| 58 | |
| 59 | ## Configuration |
| 60 | |
| 61 | **.storybook/main.ts:** |
| 62 | ```typescript |
| 63 | import type { StorybookConfig } from '@storybook/react-vite'; |
| 64 | |
| 65 | const config: StorybookConfig = { |
| 66 | stories: [ |
| 67 | '../src/**/*.mdx', |
| 68 | '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)', |
| 69 | ], |
| 70 | addons: [ |
| 71 | '@storybook/addon-essentials', |
| 72 | '@storybook/addon-a11y', |
| 73 | '@storybook/addon-links', |
| 74 | '@storybook/addon-interactions', |
| 75 | '@chromatic-com/storybook', |
| 76 | ], |
| 77 | framework: { |
| 78 | name: '@storybook/react-vite', |
| 79 | options: {}, |
| 80 | }, |
| 81 | docs: { |
| 82 | autodocs: 'tag', // Enable autodocs for tagged components |
| 83 | }, |
| 84 | staticDirs: ['../public'], |
| 85 | }; |
| 86 | |
| 87 | export default config; |
| 88 | ``` |
| 89 | |
| 90 | **.storybook/preview.ts:** |
| 91 | ```typescript |
| 92 | import type { Preview } from '@storybook/react'; |
| 93 | import '../src/tokens/index.css'; |
| 94 | import './storybook.css'; |
| 95 | |
| 96 | const preview: Preview = { |
| 97 | parameters: { |
| 98 | controls: { |
| 99 | matchers: { |
| 100 | color: /(background|color)$/i, |
| 101 | date: /Date$/i, |
| 102 | }, |
| 103 | }, |
| 104 | backgrounds: { |
| 105 | default: 'light', |
| 106 | values: [ |
| 107 | { name: 'light', value: '#ffffff' }, |
| 108 | { name: 'dark', value: '#1f2937' }, |
| 109 | { name: 'gray', value: '#f3f4f6' }, |
| 110 | ], |
| 111 | }, |
| 112 | viewport: { |
| 113 | viewports: { |
| 114 | mobile: { name: 'Mobile', styles: { width: '375px', height: '667px' } }, |
| 115 | tablet: { name: 'Tablet', styles: { width: '768px', height: '1024px' } }, |
| 116 | desktop: { name: 'Desktop', styles: { width: '1280px', height: '800px' } }, |
| 117 | }, |
| 118 | }, |
| 119 | }, |
| 120 | globalTypes: { |
| 121 | theme: { |
| 122 | description: 'Global theme', |
| 123 | defaultValue: 'light', |
| 124 | toolbar: { |
| 125 | title: 'Theme', |
| 126 | icon: 'paintbrush', |
| 127 | items: ['light', 'dark'], |
| 128 | dynamicTitle: true, |
| 129 | }, |
| 130 | }, |
| 131 | }, |
| 132 | decorators: [ |
| 133 | (Story, context) => { |
| 134 | const theme = context.globals.theme; |
| 135 | document.documentElement.dataset.theme = theme; |
| 136 | return <Story />; |
| 137 | }, |
| 138 | ], |
| 139 | }; |
| 140 | |
| 141 | export default preview; |
| 142 | ``` |
| 143 | |
| 144 | --- |
| 145 | |
| 146 | ## Story Patterns |
| 147 | |
| 148 | ### Basic Story (CSF 3.0) |
| 149 | |
| 150 | **Button.stories.tsx:** |
| 151 | ```tsx |
| 152 | import type { Meta, StoryObj } from '@storybook/react'; |
| 153 | import { fn } from '@storybook/test'; |
| 154 | import { Button } from './Button'; |
| 155 | |
| 156 | const meta: Meta<typeof Button> = { |
| 157 | title: 'Components/Button', |
| 158 | component: Button, |
| 159 | parameters: { |
| 160 | layout: 'centered', |
| 161 | docs: { |
| 162 | description: { |
| 163 | component: 'Primary UI button component with multiple variants and sizes.', |
| 164 | }, |
| 165 | }, |
| 166 | }, |
| 167 | tags: ['autodocs'], |
| 168 | argTypes: { |
| 169 | variant: { |
| 170 | control: 'select', |
| 171 | options: ['primary', 'secondary', 'ghost', 'danger'], |
| 172 | description: 'Visual style variant', |
| 173 | table: { |
| 174 | type: { summary: 'primary | secondary | ghost | danger' }, |
| 175 | defaultValue: { summary: 'primary' }, |
| 176 | }, |
| 177 | }, |
| 178 | size: { |
| 179 | control: 'radio', |
| 180 | options: ['sm', 'md', 'lg'], |
| 181 | description: 'Button size', |
| 182 | table: { |
| 183 | type: { summary: 'sm | md | lg' }, |
| 184 | defaultValue: { summary: 'md' }, |
| 185 | }, |
| 186 | }, |
| 187 | loading: { |
| 188 | control: 'boolean', |
| 189 | description: 'Shows loading spinner and disables button', |
| 190 | }, |
| 191 | disabled: { |
| 192 | control: 'boolean', |
| 193 | description: 'Disables the button', |
| 194 | }, |
| 195 | fullWidth: { |
| 196 | control: 'boolean', |
| 197 | description: 'Makes button |