<CodeLearn/>
Storybook レッスン1

Storybookの基本

コンポーネントカタログとは何か、セットアップから最初のストーリーまでを学ぼう

Storybookとは?

Storybookは、UIコンポーネントをアプリケーションから独立した環境で 開発・テスト・ドキュメント化するためのオープンソースツールです。 React、Vue、Angular、Svelte、Web Componentsなど主要なフレームワークに対応しています。

Storybookがない場合

  • コンポーネントの確認にアプリ全体の起動が必要
  • 特定の状態の再現が手間(エラー状態、ローディング等)
  • デザイナーとの認識合わせが難しい
  • コンポーネントの一覧性がない

Storybookがある場合

  • コンポーネント単体で即座に確認・操作できる
  • あらゆる状態をストーリーとして定義・再現可能
  • デザイナーもブラウザで確認できる
  • コンポーネントカタログとして一覧管理

コンポーネント駆動開発(CDD)

コンポーネント駆動開発(Component-Driven Development)は、UIを小さなコンポーネントから ボトムアップで構築していく手法です。Storybookはこの開発スタイルの中核ツールです。

1. Atoms(原子)

ボタン、入力欄、アイコンなど最小単位のUI要素

2. Molecules(分子)

検索バー(入力欄+ボタン)のようなAtomsの組み合わせ

3. Organisms(有機体)

ヘッダー、サイドバーなどMoleculesを含む複合コンポーネント

4. Pages(ページ)

Organismsを配置したページ全体のレイアウト

Storybookでは各レイヤーのコンポーネントをストーリーとして登録し、 個別に開発・テストできます。

インストールとセットアップ

Storybookは既存のプロジェクトに1コマンドで追加できます。 フレームワークやビルドツールを自動検出して最適な設定を生成してくれます。

# 既存プロジェクトにStorybookを追加
npx storybook@latest init

# 実行すると以下が自動的に行われる:
# 1. フレームワーク(React, Vue等)を検出
# 2. 必要なパッケージをインストール
# 3. .storybook/ ディレクトリに設定ファイルを生成
# 4. サンプルストーリーを作成

Next.jsプロジェクトの場合は、自動的に@storybook/nextjsが 選択され、Next.jsの機能(Image、Link、Router等)がStorybook内で動作するように設定されます。

# package.jsonに追加されるスクリプト
{
  "scripts": {
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build"
  }
}

プロジェクト構造

Storybookの設定は.storybook/ディレクトリに格納されます。 主要なファイルの役割を理解しましょう。

プロジェクトルート/
├── .storybook/
│   ├── main.ts          # Storybookの主設定ファイル
│   └── preview.ts       # ストーリー表示の共通設定
├── src/
│   └── components/
│       ├── Button.tsx
│       └── Button.stories.tsx  # ストーリーファイル
└── package.json

main.ts

ストーリーの検索パス、アドオン、フレームワーク設定を定義

// .storybook/main.ts
import type { StorybookConfig } from "@storybook/nextjs";

const config: StorybookConfig = {
  stories: ["../src/**/*.stories.@(ts|tsx)"],
  addons: [
    "@storybook/addon-essentials",
  ],
  framework: {
    name: "@storybook/nextjs",
    options: {},
  },
};

export default config;

preview.ts

すべてのストーリーに共通する設定(グローバルスタイル、デコレーター等)

// .storybook/preview.ts
import type { Preview } from "@storybook/react";
import "../src/app/globals.css"; // グローバルCSS

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
};

export default preview;

最初のストーリーを書いてみよう

ストーリーファイルは*.stories.tsxという命名規則で作成します。 コンポーネントと同じディレクトリに置くのが一般的です。

// src/components/Button.tsx
interface ButtonProps {
  label: string;
  variant?: "primary" | "secondary";
  size?: "sm" | "md" | "lg";
  onClick?: () => void;
}

export function Button({
  label,
  variant = "primary",
  size = "md",
  onClick,
}: ButtonProps) {
  const base = "rounded font-semibold transition-colors";
  const variants = {
    primary: "bg-blue-600 text-white hover:bg-blue-700",
    secondary: "bg-gray-200 text-gray-800 hover:bg-gray-300",
  };
  const sizes = {
    sm: "px-3 py-1.5 text-sm",
    md: "px-4 py-2 text-base",
    lg: "px-6 py-3 text-lg",
  };

  return (
    <button
      className={`${base} ${variants[variant]} ${sizes[size]}`}
      onClick={onClick}
    >
      {label}
    </button>
  );
}
// src/components/Button.stories.tsx
import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./Button";

const meta: Meta<typeof Button> = {
  title: "Components/Button",
  component: Button,
};

export default meta;
type Story = StoryObj<typeof Button>;

// 基本のストーリー
export const Primary: Story = {
  args: {
    label: "ボタン",
    variant: "primary",
    size: "md",
  },
};

export const Secondary: Story = {
  args: {
    label: "キャンセル",
    variant: "secondary",
  },
};
# Storybookを起動して確認
npm run storybook

# ブラウザで http://localhost:6006 が開く
# サイドバーに "Components / Button" が表示される

まとめ

  • StorybookはUIコンポーネントを独立環境で開発・テスト・ドキュメント化するツール
  • コンポーネント駆動開発(CDD)でボトムアップにUIを構築できる
  • npx storybook@latest initで既存プロジェクトに簡単に追加
  • .storybook/ディレクトリにmain.tsとpreview.tsが設定の中心
  • ストーリーファイルは*.stories.tsxの命名規則で作成する