--- id: frontend-storybook-modern title: Storybook 9 β€” component dev / test / docs category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [frontend, storybook, vibe-coding] tech_stack: { language: "TS", applicable_to: ["Frontend"] } applied_in: [] aliases: [Storybook 9, CSF 3, MDX, Chromatic, visual test, component library, design system] --- # Storybook Modern (9) > Component 의 isolated dev + test + docs. **CSF 3 (component story format), MDX, Chromatic visual test**. ## πŸ“– 핡심 κ°œλ… - λ§€ component κ°€ isolated story. - Variant (default, error, loading) κ°€ visible. - Visual test (Chromatic). - Design system μΉœν™”. ## πŸ’» μ½”λ“œ νŒ¨ν„΄ ### Setup ```bash npx storybook@latest init ``` ### CSF 3 (modern) ```tsx // Button.stories.tsx import type { Meta, StoryObj } from '@storybook/react'; import { Button } from './Button'; const meta: Meta = { component: Button, args: { children: 'Click me' }, argTypes: { variant: { control: 'select', options: ['primary', 'secondary'] }, }, }; export default meta; type Story = StoryObj; export const Primary: Story = { args: { variant: 'primary' }, }; export const Secondary: Story = { args: { variant: 'secondary' }, }; export const Disabled: Story = { args: { disabled: true }, }; ``` β†’ Args + render = story. ### Interaction (play function) ```tsx import { userEvent, within, expect } from '@storybook/test'; export const ClickAction: Story = { play: async ({ canvasElement }) => { const canvas = within(canvasElement); const btn = canvas.getByRole('button'); await userEvent.click(btn); await expect(btn).toHaveTextContent('Clicked'); }, }; ``` β†’ Story κ°€ test 도. Storybook UI μ—μ„œ step replay. ### MDX (docs + story) ```mdx import { Meta, Story } from '@storybook/blocks'; import { Button } from './Button'; # Button A primary button component. ## Variants ## API ``` β†’ Markdown + component embed. ### Chromatic (visual regression) ```bash npm i -D chromatic npx chromatic --project-token=... ``` β†’ λ§€ PR 이 visual diff. Approve / reject. ### Test runner ```bash npm i -D @storybook/test-runner npx test-storybook ``` β†’ λ§€ story 의 play κ°€ test. Headless run. ### Mock (MSW) ```tsx import { http, HttpResponse } from 'msw'; export const Loaded: Story = { parameters: { msw: { handlers: [ http.get('/api/users', () => HttpResponse.json([{ name: 'Alice' }])), ], }, }, }; ``` β†’ Real-like data. ### Theme / decorator ```tsx const meta: Meta = { decorators: [ (Story) => ( ), ], }; ``` ### Args + controls ```tsx const meta: Meta = { argTypes: { src: { control: 'text' }, size: { control: { type: 'range', min: 16, max: 128, step: 8 } }, variant: { control: 'select', options: ['circle', 'square'] }, }, }; ``` β†’ Storybook UI μ—μ„œ live tweak. ### Auto-docs ```tsx const meta: Meta = { tags: ['autodocs'], }; ``` β†’ `Docs` tab μžλ™ 생성 (props + variant). ### Vite ```js // .storybook/main.ts const config: StorybookConfig = { stories: ['../src/**/*.stories.@(ts|tsx|mdx)'], framework: { name: '@storybook/react-vite', options: {} }, addons: ['@storybook/addon-essentials', '@storybook/addon-a11y'], }; ``` β†’ Vite μΉœν™” (λΉ λ₯Έ). ### a11y addon ```bash npm i -D @storybook/addon-a11y ``` β†’ λ§€ story κ°€ axe 검증. ### Build (deploy) ```bash npm run build-storybook # β†’ static-storybook/ 에 deploy. ``` β†’ Vercel / Netlify / GitHub Pages. ### Use case ``` - Design system (Bento, Radix UI examples). - Component library showcase. - Cross-team review. - QA reproduction. - Visual regression. - Onboarding (이 component κ°€ 무엇). ``` ### vs Histoire / Ladle / React Cosmos ``` Histoire: Vue μΉœν™”. Ladle: lighter, faster. React Cosmos: legacy. Storybook: κ°€μž₯ mature. β†’ Storybook κ°€ default. ``` ### Performance ``` Storybook 9: 빠름 (Vite default). 큰 codebase: 1000+ story κ°€ OK. β†’ λ§€ story file κ°€ lazy load. ``` ### Production tips ``` - λ§€ component 의 λ§€ variant. - Edge case (loading, error, empty). - Long content (truncation). - Different size / theme. - A11y test 항상. - Visual diff CI gate. ``` ### CI integration ```yaml - run: npm run build-storybook - run: npx test-storybook --url http://localhost:6006 - run: npx chromatic ``` ### Composition (multi-storybook) ```ts // .storybook/main.ts const config = { refs: { 'design-system': { url: 'https://design.example.com' }, 'component-library': { url: 'https://components.example.com' }, }, }; ``` β†’ λ‹€λ₯Έ storybook κ°€ 1 navigation. ### Args from URL ``` ?args=variant:primary;size:lg ``` β†’ Bookmark / share. ### Custom addon ```ts // addon-my-feature/manager.ts import { addons, types } from '@storybook/manager-api'; addons.register('my-addon', () => { addons.add('my-addon/panel', { type: types.PANEL, title: 'My Panel', render: ({ active }) =>
Custom UI
, }); }); ``` ### LLM 도움 ``` - Story generation (component β†’ variant). - Visual diff explanation. - A11y violation fix. ``` ### 함정 ``` - λͺ¨λ“  story κ°€ λ§€ λ³€κ²½ = Chromatic cost. - Story κ°€ stale (component λ³€κ²½ ν›„ μ•ˆ update). - Decorator κ°€ prod κ°€ λ‹€λ₯Έ (theme). - Args κ°€ λ„ˆλ¬΄ 많음 = noisy. - Build κ°€ slow (큰 codebase). ``` ## πŸ€” μ˜μ‚¬κ²°μ • κΈ°μ€€ | μž‘μ—… | μΆ”μ²œ | |---|---| | Component dev | Storybook | | Visual test | Chromatic + Storybook | | Design system | Storybook + composition | | Vue | Histoire / Storybook | | μž‘μ€ / 빠름 | Ladle | | Documentation | MDX + autodocs | ## ❌ μ•ˆν‹°νŒ¨ν„΄ - **Story μ•ˆ maintain**: stale. - **No edge case**: production κ°€ first μ§„μ‹€. - **Storybook + Cypress λ‘˜ λ‹€ component test**: redundant. - **No visual diff**: silent regression. - **No a11y test**: accessibility 깨짐. ## πŸ€– LLM ν™œμš© 힌트 - CSF 3 κ°€ modern. - Chromatic + Storybook κ°€ visual test. - Play function κ°€ interaction test. - a11y addon 항상. ## πŸ”— κ΄€λ ¨ λ¬Έμ„œ - [[Testing_Visual_Regression]] - [[Frontend_Design_Tokens]] - [[Frontend_shadcn_Radix_Patterns]]