Storybook を活用した UI カタログ整備と開発効率の向上

Storybook を活用した UI カタログ整備と開発効率の向上
2024/09/10に公開

背景と課題

SaaSサービスを自社開発・運用している企業様からのご依頼です。サービスのリリースから約4年が経過し、機能追加を繰り返す中でコードベースが徐々に複雑化。加えて、チームの人員交代が続いたことで、コンポーネントの仕様共有や保守性の低下が大きな課題として浮き彫りになっていました。

特にUI実装のフェーズでは、デザイナーと開発者の間でコンポーネント仕様の認識ズレが生じやすく、次のような問題が慢性化していました。

  • 実装後に修正依頼が多発し、開発工数が増大
  • 開発者ごとに仕様解釈が異なり、似たようなコンポーネントが乱立
  • UIの一貫性が失われ、再利用性も低下
  • E2Eテストだけでは UI 崩れを検知できず、品質リスクが増大

アプローチ:Storybook 導入による UI 開発の再構築

このような課題に対し、UIの仕様・状態・挙動を1ヶ所で管理できる「Storybook」を導入。デザイナーと開発者が共通の「UI言語」を持つ状態を作ることを目指しました。

UIカタログの整備とコンポーネント設計の標準化

すべてのUIコンポーネントをStorybookに登録・カタログ化することで、次のような変化が生まれました。

  • デザイナーが事前にStorybookを確認することで、「実装してから修正」ではなく「実装前に確認」が可能に
  • 開発チーム間での再利用が進み、UIの断片化がストップ
  • デザインルールに基づいたコンポーネント単位での開発が標準化され、保守性が向上

Image from Gyazo

引用元:https://storybook.js.org/

自動テストによる品質の担保

開発効率を向上させるために、Storybook のテスト機能も活用しました。

  • スナップショットテストの導入(Jest + Storybook)
    • コンポーネントの UI 変更が意図したものかどうかを検証
  • インタラクションテストの追加(Testing Library + Storybook)
    • ボタンのクリックやフォーム入力時の挙動を事前に確認
  • Visual Regression Test の適用(Playwright + Storybook)
    • UI の崩れを自動検知し、リグレッションの防止

コラボレーションの強化と運用改善

デザイナーと開発者が Storybook を共通のリファレンスとして使うことで、コミュニケーションが非同期かつ明確に。

  • PRにStorybookの該当リンクを添えることで、仕様確認・レビューの効率が向上
  • コンポーネント単位での設計が浸透し、デザイナーからのフィードバックが「イメージ」でなく「事実」ベースに変化
  • 仕様の変更点も Storybook を通じて即座にチームに伝達可能に

なぜ Storybook を選んだのか?

NotionやMiroなどによる仕様管理も選択肢にありましたが、以下の理由から Storybook を採用しました。

  • 実際に動作するUIをそのままカタログとして共有できる
  • テスト・ドキュメント・アクセシビリティチェックとの統合が可能
  • 開発者だけでなく、デザイナーや非エンジニアも確認・参加できる導線が整っている

Before / After 比較

項目 導入前 導入後
UI実装の手戻り デザイナー確認後の修正依頼が多く、開発が長期化 実装前に動作確認が可能に。修正依頼が40%減少
コンポーネントの再利用性 パーツごとに個別実装。類似UIが乱立 UIの統一と再利用が進み、再利用率60%増加
開発スピード デザイン仕様の確認・調整に時間がかかる UI仕様が明確になり、開発スピードが25%向上
品質の担保 見た目崩れの検出が属人的 テストと連携した自動UI確認により品質を安定化

実践例:Switch コンポーネントに見る Storybook 運用の実際

導入した Storybook を使って、以下のように UI コンポーネントを定義・テストしています。

✅ Switch コンポーネントの実装例

components/Switch/index.tsx

import clsx from "clsx";
import { forwardRef } from "react";
import styles from "./styles.module.css";

type Props = {
  variant?: "small";
} & Omit<React.ComponentPropsWithoutRef<"input">, "type" | "role">;

export const Switch = forwardRef<HTMLInputElement, Props>(function Switch(
  { className, ...props },
  ref
) {
  return (
    <span className={clsx(className, styles.module)}>
      <input {...props} ref={ref} type="checkbox" role="switch" />
      <span />
    </span>
  );
});
components/Switch/styles.module.css
.module {
  position: relative;
  display: inline-block;
  width: 58px;
  height: 32px;
  border-radius: 32px;
  border: 2px solid var(--light-gray);
}

.module input {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  z-index: 2;
  cursor: pointer;
}

.module input + span {
  display: block;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  border-radius: 32px;
  transition-duration: 0.2s;
}

.module input:checked + span {
  background-color: var(--blue);
}

.module input + span::after {
  content: "";
  display: block;
  width: 24px;
  height: 24px;
  border-radius: 12px;
  position: absolute;
  top: 2px;
  left: 2px;
  box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.6);
  background-color: var(--white);
  transition-duration: 0.2s;
}

.module input:checked + span::after {
  transform: translateX(26px);
}

.module input:disabled {
  pointer-events: none;
}

.module input:disabled + span {
  opacity: 0.4;
}

📚 Storybook による状態定義と可視化

  • CheckedDisabledChecked など、状態ごとの UI を一覧で確認・テストできるように
  • PRにこの Storybook を添えることで、「仕様にない見た目」や「使えない状態」を事前に防止
  • a11y(アクセシビリティ)チェックの設定も明示的に管理
components/Switch/Switch.stories.tsx

import { ComponentMeta, ComponentStoryObj } from "@storybook/react";
import { Switch } from "./";

export default {
  component: Switch,
  parameters: {
    a11y: {
      config: { rules: [{ id: "label", enabled: false }] },
    },
  },
} as ComponentMeta<typeof Switch>;

type Story = ComponentStoryObj<typeof Switch>;

export const Default: Story = {};

export const Checked: Story = {
  args: { defaultChecked: true },
};

export const Disabled: Story = {
  args: { disabled: true },
};

export const DisabledChecked: Story = {
  args: { disabled: true, defaultChecked: true },
};

Storybookでの確認イメージ

Image from Gyazo

成果と今後の展望

Storybook の導入によって、以下のような成果が得られました。

  • リリース後の修正依頼が 40% 減少
  • 開発スピードが 25% 向上(仕様確認や UI の再利用が容易になったため)
  • コンポーネントの再利用率が 60% 増加(新規 UI の開発工数を削減)
  • デザイナーと開発者のコミュニケーションミスが激減

今後は、Storybook のアドオン機能をさらに活用し、アクセシビリティチェック・ドキュメント自動生成・Figma連携などを通じて、より包括的な UI 開発・運用基盤の構築を目指していきます。

Xでシェア
Facebookでシェア
LinkedInでシェア

お問い合わせ

開発・セキュリティ・品質を包括的に見直し、
持続可能なプロダクト開発をサポートします。

お問い合わせ