コンポーネント設計
部品は、外から変えられるものを絞るほど長持ちします。何でも変えられる部品は、部品ではありません。
図の中身を文字で読む
- ✕ 真偽値を足し続ける ○ 排他的な列挙+スロット
- isPrimary isDanger isLarge variant: "primary" | "danger" | "ghost"
- hasIcon isFullWidth isLoading size: "sm" | "md" | "lg"
- children: 中身はそのまま差し込む
- 組み合わせが 2の6乗=64通り
- isPrimary と isDanger が同時に真になれてしまう 無効な状態が、そもそも表現できない
- コンポジション:器だけを提供し、中身は使う側が組む
- Card.Media
- Card.Body
- Card.Footer
- カードは「どこに何が入るか」だけを決める。
- 中身が画像かバッジかボタンかは知らない。
- 差し込める場所を3つに限定すれば、自由度と一貫性が両立する。
- よく使う組み合わせはプリセットとして別途用意する。
- すべてを組み立てさせると、単純な用途で記述量が増える。
ひと目で#
- コンポーネント
- 独立して再利用できる部品。見た目と振る舞いを1つにまとめたもの
- バリアント
- 同じ部品が取りうる型。互いに排他な列挙にする
- コンポーネントAPI
- 外から何を変えられるかの設計。変えてよいものだけを開く
- スロット
- 中身を差し込む口。文言やアイコンは引数ではなく、ここで受ける
- コンポジション
- 機能を足すのではなく、小さな部品を組み合わせる方針
- アトミックデザイン
- 粒度を5段階(原子、分子、生体、テンプレート、ページ)で共有する枠組み
使い分け#
図の中身を文字で読む
- 部品の輪郭=開いてよい口を3つに限る
- 開く口
- variant / size
- 排他の列挙値
- children
- 文言・アイコンはここ
- --button-bg
- 局所の例外はトークンで
- Button の中身
- 見た目・状態・キー操作・
- フォーカス・押せる大きさは部品の内側で決める
- 中で決めたものは、外から壊せない
- 開かない口
- className / style
- 何でも上書きでき、揃いが崩れる
- label: string
- リンクや強調を含む文言に応えられない
- isPrimary / isDanger
- 口を絞るほど、直す場所が1か所に集まる
- フォーカスの色を変えたい。口が3つなら、部品の中を1回直せば全画面に届く。
- style を素通ししていると、上書きしている箇所を全部探して回ることになる。
- 迷ったら閉じておく。あとから開くのは容易で、開いた口を閉じるのは難しい。
外から何を渡せるかは、渡し方で3つに分かれます。渡せないものを決めるほうが、部品は長持ちします。
| 受け取るもの | 受け方 |
|---|---|
| 型、サイズ、状態、識別子 | プロパティ(列挙値) |
| 文言、アイコン、任意の子要素 | スロット |
| 部品固有の色や余白の例外 | コンポーネントトークン(CSS 経由) |
| こういうとき | どうする |
|---|---|
| 役割の違いを表したい | バリアント。3〜4種まで |
| 構造や振る舞いが違う | 別の部品にする |
| 中身の構成が用途ごとに変わる | コンポジション |
| よく出る組み合わせがある | プリセットを別に用意する |
粒度で判断が割れたら、同じ部品を実物のデザインシステムから2つ選んで見比べます。分かれた箇所が、その部品の難しいところです。
間違えやすいところ#
- 真偽値のプロパティを増やす
isPrimaryとisDangerが同時に真になれてしまう。1つの列挙値にする - 文言を文字列のプロパティで受ける装飾やリンクを含む要求に応えられない
classNameやstyleを素通しする何でも上書きでき、揃いが崩れる- 見た目だけ揃えて振る舞いを揃えないフォーカスやキー操作が部品ごとに違うと、学習が効かない
- 2か所目で共通化する3か所目で例外が出て、破綻しやすい
- アトムに余白を持たせる配置は上位が決める。アトムが外側の余白を持つと、置き方の自由が失われる
- 分類の厳密さで議論を止めるアトムかモルキュールかより、使える粒度を優先する
仕様シートを書く#
この値は作業台で決められます。和文の予約ページに載せて、幅と明暗を替えて確かめてから CSS を持ち帰る: 部品がトークンに追従する
部品を足す前に、このシートを1枚書きます。役割・状態・使ってはいけない場面が埋まらないうちは、部品の輪郭がまだ固まっていない合図です。見本は架空のECのボタンです。部品名と中身を差し替えて使ってください。
下書きの元を切り替えると、記入欄は選んだ内容に置き換わります。
空欄のテンプレは次のとおりです。上の記入欄に呼び出しても、ここからコピーしても、中身は同じです。
# コンポーネント仕様: (部品名)
作成: (日付) / 判断者: (承認する人)
対象: (使う画面の範囲)
## 役割
(何のための部品か。1〜2文)
(似ている部品と、何が違うか)
## バリアント(互いに排他・4種まで)
- (名前) : (使う場面)
## サイズ
- (段) : (既定はどれか。場所を限る段は、その場所も書く)
## 状態
default / hover / focus-visible / active / disabled / loading のうち持つもの
- (disabled の理由をどこに出すか)
- (loading 中の連打をどう止めるか)
## 使ってはいけない場面
- (この部品で作ってはいけないもの。代わりに何を使うか)
## 実装メモ
- (プロパティで受けるもの/スロットで受けるもの)
- (参照するトークン)
- (フォーカスとキー操作)
この道具は JavaScript で動きます。無効の場合は、下のテンプレを写して使ってください。
実装#
type ButtonProps = {
variant?: "primary" | "secondary" | "ghost" | "danger"; // 排他
size?: "sm" | "md" | "lg";
disabled?: boolean;
children: React.ReactNode; // 中身はスロットで受ける
};
このコードで動いている見本です
直す例#
架空の案件を1つ例にとります。どこを見て、何をどう直すかを書きます。
例として、管理画面の Button に、プロパティが9つ付いています。isPrimary isDanger isLarge isFullWidth hasIcon …。実装を検索すると、isPrimary と isDanger が両方 true になっている呼び出しが3か所ありました。どちらの見た目で出るかは CSS の書き順で決まっていて、誰も意図していません。
畳み方は決まっています。同時に真になってはいけないものは、1つの列挙値にまとめる。 variant: "primary" | "secondary" | "ghost" | "danger" の1本にすれば、矛盾した組み合わせはそもそも書けなくなります。isLarge は size の段へ、hasIcon は不要です。アイコンを渡すかどうかは、渡された中身を見れば分かります。
残った isFullWidth は、見た目ではなく置き方の指定でした。これは部品の中ではなく、置く側のレイアウトで決めます。ボタンが自分の幅を知っているべきではありません。
9つのうち手元に残ったのは variant size disabled と、中身を受ける children だけです。何を残すかの線引きに迷ったら、下の仕様シートに「使ってはいけない場面」まで書いてみます。そこが書けない部品は、まだ輪郭が決まっていません。
確認する#
- バリアントの値を、口に出して最後まで数えられる
- 同じプロパティの組み合わせで、出力される HTML の構造が変わらない
- 部品の外から
classNameやstyleで見た目を上書きしている箇所がない
使えるパターン#
このページで扱う語#
このページで扱う語を並べる本文では太字6 語
語の名前から引くなら用語索引へ。
- アトム
- アトミックデザインにおける最小単位の部品。それ以上分解すると意味を失うもの。
- モルキュール
- 複数のアトムを組み合わせ、単独で1つの機能を果たすようにした部品。
- オーガニズム
- アトムとモルキュールを組み合わせ、画面の独立した一区画として成立する大きな部品。
- UIキット
- デザインツール上で再利用できる部品の素材集。実装とは切り離されている。
- パターンライブラリ
- 再利用可能な UI 部品と、その使い方をまとめた一覧。
- Storybook
- コンポーネントを画面から切り離して単独で表示・確認できるようにする開発ツール。
この話が要る場面#
このページが答えになる、現場の困り事です。困り事の側から探すと、同じ場所に着きます。
同じ形が3回出たら部品にする。2回目までは複製でよい。
同じ形が3回出たら .card 等に切り出す
真偽値の指定が並んでいるなら、組み合わせで持たせる形に変える。
.button--primary { /* 組み合わせで持つ */ }
.button--large { /* size + variant */ }この場面のほかの困り事と、そのまま貼れる部品は同じものを同じに作るにまとめてある。逆引きには全188件。
出典#
- Brad Frost『Atomic Design』
- Material Design 3