---
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<typeof Button> = {
  component: Button,
  args: { children: 'Click me' },
  argTypes: {
    variant: { control: 'select', options: ['primary', 'secondary'] },
  },
};
export default meta;

type Story = StoryObj<typeof Button>;

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';

<Meta title='Button' component={Button} />

# Button

A primary button component.

## Variants

<Canvas>
  <Story name='Primary'>
    <Button variant='primary'>Primary</Button>
  </Story>
</Canvas>

## API

<ArgTypes />
```

→ 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) => (
      <ThemeProvider theme={theme}>
        <Story />
      </ThemeProvider>
    ),
  ],
};
```

### Args + controls
```tsx
const meta: Meta<typeof Avatar> = {
  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 }) => <div>Custom UI</div>,
  });
});
```

### 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]]
