前回は環境構築を行いました。今回はより実践的なコンポーネントの作り方を解説していきます。
単なるパーツの切り出しではなく、再利用性と保守性を考慮したコンポーネントの設計方法を、具体的なコード例と共にご紹介します。
静的サイトでのStorybook活用について
通常の静的サイト開発では、テンプレートエンジンを使いコンポーネントはページ単位で管理されることが一般的です。それらをstorybook同期する方法で活用します。
この記事では、Storybookをコンポーネントのプレビューとドキュメント化のツールとして使用する方法を解説します。
このアプローチには以下のようなメリットとデメリットがあります:
- メリット
- 実際のサイトのHTMLをそのままStorybookで確認できる
- コンポーネントの見た目とバリエーションを管理できる
- チーム内での共有・レビューが容易になる
- デメリット
- 実際のサイトとStorybookで二重管理になる
- HTMLの更新時は両方を修正する必要がある
これらを理解した上で、実装方法を見ていきましょう。
目次 [hide]
1. 初期ファイルのクリーンアップ
まずは、Storybookの初期ファイルを整理します:
bash
# storiesディレクトリ内の初期ファイルを削除
rm -rf stories/assets
rm stories/Button.stories.js
rm stories/Header.stories.js
rm stories/Page.stories.js
rm stories/button.css
rm stories/header.css
rm stories/page.css
rm stories/Button.js
rm stories/Header.js
rm stories/Page.js
rm stories/Configure.mdx
2. コンポーネントのプレビュー管理
実際のサイトで使用しているHTMLコンポーネントをStorybookで管理していきましょう。
基本的なボタンコンポーネント
javascript
// stories/components/button.stories.js
export default {
title: 'Components/Button',
argTypes: {
text: { control: 'text' },
variant: {
control: { type: 'select' },
options: ['primary', 'secondary', 'outline'],
},
size: {
control: { type: 'select' },
options: ['small', 'medium', 'large'],
},
},
};
// 実際のサイトのボタンHTMLを再現
export const Primary = {
render: (args) => `
<button class="btn btn-${args.variant} btn-${args.size}">
${args.text}
</button>
`,
args: {
text: '送信する',
variant: 'primary',
size: 'medium'
}
};
ナビゲーションコンポーネント
javascript
// stories/components/navigation.stories.js
export default {
title: 'Components/Navigation',
};
// グローバルナビゲーション
export const GlobalNav = {
render: () => `
<nav class="global-nav">
<ul>
<li><a href="#" class="nav-item">ホーム</a></li>
<li><a href="#" class="nav-item">サービス</a></li>
<li><a href="#" class="nav-item">会社概要</a></li>
<li><a href="#" class="nav-item">お問い合わせ</a></li>
</ul>
</nav>
`
};
カードコンポーネント
javascript
// stories/components/card.stories.js
export default {
title: 'Components/Card',
argTypes: {
title: { control: 'text' },
content: { control: 'text' },
hasImage: { control: 'boolean' },
},
};
export const Default = {
render: (args) => `
<div class="card">
${args.hasImage ? '<img src="/api/placeholder/400/200" alt="placeholder" class="card-img">' : ''}
<div class="card-body">
<h3 class="card-title">${args.title}</h3>
<p class="card-text">${args.content}</p>
</div>
</div>
`,
args: {
title: 'カードタイトル',
content: 'これはカードのコンテンツです。説明文をここに入れることができます。',
hasImage: true
}
};
3. ドキュメントの追加
コンポーネントの使用方法を説明するドキュメントを追加します:
javascript
// stories/components/button.stories.js
export default {
title: 'Components/Button',
parameters: {
docs: {
description: {
component: `
# ボタンコンポーネント
サイト全体で使用する標準的なボタンコンポーネントです。
## 使用方法
\`\`\`html
<button class="btn btn-primary btn-medium">送信する</button>
\`\`\`
## サイズバリエーション
- small: 小さめのボタン(サブアクション用)
- medium: 標準サイズ(基本的な操作用)
- large: 大きめのボタン(主要なCTA用)
## 注意事項
- ボタンのテキストは最大20文字までにしてください
- アイコンを使用する場合は左側に配置してください
`
}
}
},
// ...既存のコード
};
4. コンポーネントの状態管理
ホバーやアクティブなどの状態も確認できるようにします:
javascript
// stories/components/button.stories.js
export const States = {
render: () => `
<div style="display: flex; gap: 16px;">
<button class="btn btn-primary">Normal</button>
<button class="btn btn-primary hover">Hover</button>
<button class="btn btn-primary active">Active</button>
<button class="btn btn-primary" disabled>Disabled</button>
</div>
`
};
5. レスポンシブ対応の確認
javascript
// stories/components/card.stories.js
export const Responsive = {
parameters: {
viewport: {
defaultViewport: 'mobile1'
}
},
render: (args) => `
<div class="card card-responsive">
<!-- カードの内容 -->
</div>
`
};
まとめ:コンポーネント制作のポイント
実際のHTMLサイトのコンポーネントをStorybookで管理する方法について、以下のポイントを解説してきました:
- コンポーネントのプレビュー管理
- 実際のサイトのHTMLをストーリーとして再現
- argTypesを活用したバリエーション管理
- コンポーネントの見た目を一覧で確認
- ドキュメントの重要性
- 使用方法の明確な説明
- サイズやバリエーションの一覧
- チーム共有のための注意事項
- 状態管理の実装
- ホバーやアクティブなどの状態確認
- 無効状態の表示
- 各状態のスタイル管理
- レスポンシブ対応
- 各ブレイクポイントでの表示確認
- モバイルファーストの考え方
- ビューポート切り替えによるテスト
次回予告:実践活用編
次回は、より実践的なコンポーネント管理について解説します:
- フォームやカードなどの複雑なコンポーネント
- コンポーネントの組み合わせパターン
- アクセシビリティの確認方法
- チームでの運用テクニック
実際のプロジェクトでStorybookを活用する際は、この記事で解説した基本的な管理方法を土台として、プロジェクトの要件に合わせてカスタマイズしていくことをお勧めします。