Storybook
UI コンポーネントをアプリ本体から切り離した環境で描画し、状態ごとの見た目と操作を確認・テスト・文書化する開発環境
Storybook とは
Storybook は、UI コンポーネントをアプリ本体から切り離して描画するための開発環境である。アプリとは別のビルドを立て、対象のコンポーネントだけをマウントして表示するので、ログインや画面遷移をたどらずに目的の状態を直接出せる。この 1 つの状態を Story と呼び、名前を付けて並べたものがカタログになる。
利点と代償は同じ性質から来る。ルーティングやデータ取得を通らないから速く確実に再現できる一方、コンポーネントが本来受け取っていた依存 (Context、ルーター、通信の応答) は自分で用意しなければ再現されない。差し替えが増えるほど、Storybook で緑なのに本番では崩れるという乖離の余地も広がる。
Story の書き方
Storybook が解釈するのは、このファイルの export の形である。default export の meta が対象コンポーネントと共通設定を宣言し、名前付き export のそれぞれが 1 つの Story になる。この規約を CSF (Component Story Format) と呼ぶ。
args はコンポーネントに渡す入力で、Story ごとに違う部分だけを書けばよい。tags: ['autodocs'] を付けると、型定義と args から説明ページが生成される。ファイルの正体は単なる ES モジュールなので、Storybook の外 (単体テストなど) からも import して同じ引数で描画できる。
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
component: Button,
tags: ['autodocs'],
};
export default meta;
type Story = StoryObj<typeof Button>;
export const Primary: Story = {
args: { variant: 'primary', children: 'Click me' },
};
export const Secondary: Story = {
args: { variant: 'secondary', children: 'Cancel' },
};
export const Disabled: Story = {
args: { variant: 'primary', children: 'Submit', disabled: true },
};
export const Loading: Story = {
args: { variant: 'primary', children: 'Saving...', loading: true },
};
メリット
API やルーティングなしでコンポーネントを独立して開発でき、正常・エラー・ローディング・空状態を一覧で確認できる。Props の自動ドキュメント生成、スクリーンショット比較によるビジュアルテスト、Chromatic を使ったデザイナーとの協業も可能だ。
インタラクションテスト
Story に play を付けると、描画が終わった直後にその操作が自動で流れる。中で使うのは操作を模した API とアサーションで、Storybook 9 以降は本体パッケージの storybook/test から import する (@storybook/test は 8 系で更新が止まっている。2026 年 8 月時点の最新は 10 系で、10.0.0 は 2025 年 10 月の公開)。手で触って確かめていた確認手順を Story 側に書き移せるので、状態の再現とその後の操作を 1 か所にまとめられる。
import { within, userEvent, expect } from 'storybook/test';
export const Submitted: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.type(canvas.getByLabelText('Email'), 'alice@example.com');
await userEvent.click(canvas.getByRole('button', { name: 'Submit' }));
await expect(canvas.getByText('送信完了')).toBeInTheDocument();
},
};
Chromatic (ビジュアルリグレッションテスト)
ビジュアルリグレッションテストは、Story ごとに撮った画像を前回の結果と比べ、差分を人に見せる仕組みである。Chromatic はこれを Storybook の配信と組み合わせた外部サービスで、CI 側の仕事はビルドして送ることだけになる。
# GitHub Actions で Chromatic を実行
- uses: chromaui/action@v18 # 2026 年 8 月時点の最新メジャー
with:
projectToken: ${{ secrets.CHROMATIC_TOKEN }}
PR ごとに画像を比較し、意図しない表示の変化を拾う。ただし差分の良し悪しは機械には決められないため、承認するか却下するかは人が判断する。この承認を運用に組み込まないと差分が出たまま放置され、やがて誰も結果を見なくなる。
テストピラミッドでの位置づけ
同じ画面を扱っていても、層ごとに確かめている対象が違う。
| テスト | ツール | 確かめる対象 |
|---|---|---|
| 単体テスト | Vitest | 入力に対する出力・状態の遷移 |
| コンポーネントテスト | Storybook | コンポーネント 1 つの表示と操作 |
| ビジュアルリグレッション | Chromatic 等 | 前回との見た目の差分 |
| E2E テスト | Playwright | 画面をまたぐ導線と本物の依存 |
Storybook が受け持つのはコンポーネント 1 つに閉じた範囲である。複数画面をまたぐ流れや実際の通信を含む挙動は E2E の担当で、そこまで Storybook で代替しようとすると、依存を差し替える仕掛けの保守が本体の開発より重くなる。
Story を腐らせないための線引き
Story はアプリの状態を再現する場所ではなく、入力の組み合わせを並べる場所と割り切る。1 つの Story に画面遷移や複数段の通信を詰め込むと、失敗したときに何が壊れたのか切り分けられなくなる。
導入して数か月で価値が落ちる原因は、たいてい Story の数ではなく更新の途切れである。コンポーネントを直したときに Story も直す動機を作るには、Story をテストの入力として使い回すのが手堅い。単体テストが同じ Story を読んでいれば、放置された Story はテストの失敗として表に出る。
見た目の差分は、承認する経路を先に決めてから導入する。判断する人が決まっていない差分検出は、警告が積み上がるだけで何も守らない。
この記事は役に立ちましたか?
関連用語
関連する記事
テスト本ガイド - テスト設計を学べる技術書の選び方
テストの書き方からテスト戦略まで学べる技術書の選び方を紹介。テストピラミッド、TDD の正しい読み方、テストの ROI の考え方を解説します。
バグを生むのは知識不足ではなく想像力不足である
バグの多くは、コードを書いた時点で「こういうケースもありうる」と想像できなかったことが原因です。想像力を鍛える読書法と、エッジケースへの感度を高める方法を解説します。
スマホ / パソコン入門書の選び方 - シニアの家族に贈る 1 冊の見つけ方
スマホとパソコンの入門書を「贈る側 / 教える側」の視点で選ぶガイド。機種と OS の一致、文字の大きさ、年度の確認という 3 条件と、Android / iPhone / Windows 11 それぞれの定番書、安全対策の 1 冊まで 2026 年 8 月時点の収載書から紹介します。