Storybook入門:React TypeScriptでコンポーネントのStoryを書く

スポンサーリンク

Storybook入門:React TypeScriptでコンポーネントのStoryを書く

Storybookとは

StorybookはUIコンポーネントをアプリから切り離して、独立した環境で開発・確認できるツールです。

通常の開発:アプリを起動 → 特定の画面まで遷移 → コンポーネントを確認
Storybook:コンポーネントを直接開いてpropsを変えながら確認
  • コンポーネントの全状態(バリアント・エラー・空状態など)を一覧できる
  • デザイナーとの確認・ドキュメントとして使える
  • React・Vue・Angularなど主要フレームワークに対応

セットアップ

Vite + React + TypeScript のプロジェクトに追加します。

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npx storybook@latest init

storybook init がプロジェクトを自動検出して必要なパッケージをインストールします。完了後に起動します。

npm run storybook
# http://localhost:6006 でStorybookが開く

コンポーネントを作る

例として Button コンポーネントを用意します。

// src/components/Button.tsx
type ButtonProps = {
  label: string
  variant?: 'primary' | 'secondary'
  size?: 'small' | 'medium' | 'large'
  disabled?: boolean
  onClick?: () => void
}

export function Button({
  label,
  variant = 'primary',
  size = 'medium',
  disabled = false,
  onClick,
}: ButtonProps) {
  const base = 'px-4 py-2 rounded font-medium'
  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 = {
    small: 'text-sm px-3 py-1',
    medium: 'text-base',
    large: 'text-lg px-6 py-3',
  }

  return (
    <button
      className={`${base} ${variants[variant]} ${sizes[size]}`}
      disabled={disabled}
      onClick={onClick}
    >
      {label}
    </button>
  )
}

Storyを書く(CSF3形式)

Story ファイルはコンポーネントと同じディレクトリに .stories.tsx として置きます。

// src/components/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './Button'

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

export default meta
type Story = StoryObj<typeof Button>

export const Primary: Story = {
  args: {
    label: '送信する',
    variant: 'primary',
  },
}

export const Secondary: Story = {
  args: {
    label: 'キャンセル',
    variant: 'secondary',
  },
}

export const Large: Story = {
  args: {
    label: '大きいボタン',
    size: 'large',
  },
}

export const Disabled: Story = {
  args: {
    label: '送信できません',
    disabled: true,
  },
}

args に渡したオブジェクトがそのままコンポーネントのpropsになります。Storybook上でControls(UIパネル)から値を変えて動作確認もできます。


Meta の主なオプション

const meta: Meta<typeof Button> = {
  component: Button,
  title: 'Components/Button',    // サイドバーの階層(省略可)
  args: {                         // 全Storyに共通のデフォルトargs
    label: 'ボタン',
  },
  argTypes: {                     // Controlsパネルの表示設定
    variant: {
      control: 'select',
      options: ['primary', 'secondary'],
    },
    onClick: { action: 'clicked' }, // クリックをActionsパネルに表示
  },
}
プロパティ 説明
component 対象コンポーネント(必須)
title サイドバーの表示パス。'Forms/Button' のように階層化できる
args 全Storyに適用するデフォルトprops
argTypes Controlsの入力タイプや説明を設定

Storyの継承(argsの上書き)

meta.args で共通のデフォルトを設定し、各Storyで上書きできます。

const meta: Meta<typeof Button> = {
  component: Button,
  args: {
    label: 'ボタン',   // 全Storyのデフォルト
    size: 'medium',
  },
}

export const Primary: Story = {
  args: { variant: 'primary' },  // labelとsizeはmetaから継承
}

export const Secondary: Story = {
  args: { variant: 'secondary' },
}

ファイル構成

src/
  components/
    Button.tsx
    Button.stories.tsx   ← Storyファイル
    Input.tsx
    Input.stories.tsx

コンポーネントと同じディレクトリに置くのが一般的です。.storybook/main.tsstories'../src/**/*.stories.tsx' が設定されており、このパターンにマッチするファイルが自動で読み込まれます。


まとめ

概念 説明
Story コンポーネントの1つの状態を記述したもの
args Storyに渡すprops。ControlsパネルからGUIで変更できる
Meta コンポーネント全体の設定(title, args, argTypesなど)
StoryObj TypeScriptでStoryを型安全に定義するための型
  • export default meta でコンポーネントを登録し、export const XXX: Story で各状態を定義する
  • args でpropsを渡すと、ControlsパネルからGUIで変更して動作確認できる
  • meta.args に共通のデフォルトを置き、各StoryのargsでそれぞれのVariantを表現するのが基本パターン

Storybookで確認したコンポーネントの動作をさらにデバッグしたい場合は「React DevTools Components:コンポーネントの状態をリアルタイムで確認する」も参照してください。

アプリ全体のE2Eテストには「Playwright入門:TypeScriptでE2Eテストを書く」も参照してください。