夜七時

2025-12-22

UIコンポーネント設計の考え方

ここで扱いたいのは、実装の細かいコードではなく、

  • どんなレイヤーでコンポーネントを分けて考えるか
  • コンポーネントをむやみに増やさないための基準
  • Button や Form など、代表的なパーツごとの方針

といった部分です。

コンポーネントをレイヤーで捉える

アトミックデザインの考え方をベースにして、コンポーネントをざっくり次のレイヤーで捉えます。

このレイヤー分けをする事で、

  • 「どのレイヤーの話をしているのか」をチームで共有しやすくすること
  • 部品を追加すると、どこまで波及するかイメージしやすくすること

ができます。

Atom(部品レベル)

例:ボタン、アイコン、テキスト、入力欄、チェックボックス など。

単体で意味を持ち、画面のいろいろな場所で再利用されるパーツ。

Molecule / Organism(小さなまとまり)

例:ラベル+入力欄+エラーメッセージのセット、検索フォーム、カード など

Atom を組み合わせて「ひとまとまりの機能」として使う単位。

Template(画面のセクション〜全体)

例:監視ツールのサマリーヘッダー、ライン一覧+詳細パネル、設定画面の 1 セクション など

Molecule を組み合わせて「画面の大きな塊」を作る単位。

レイヤー分けの判断の例
  • 「他の場所でも同じものを使いたい」は Atom / Molecule
  • 「この画面だけの都合で成立している」は Organism 側

くらいに思っておくと整理しやすいです。

コンポーネントを増やす前に考えるべき事

新しいコンポーネントを追加したり、既存のものに似た UI を作る前に、次のチェックをお勧めします。

既存のコンポーネントで代用できないか?
  • 既に似た役割の Button / Input / Card がないか探す
  • Figma等でコンポーネント集を作っておくと、後に確認しやすい

既存を少し拡張する方が自然ではないか?
  • variant や size を 1つ追加するだけで足りないか
  • 既存のスタイルを流用しつつ、用途だけ変えられないか

“命名できるレベルの違い”があるか?
  • 「なんとなく見た目が違う」ではなく 、「役割や使う文脈が明確に違う」と説明できるかどうか

将来のメンテナンスを想像したとき、分かりやすいか?
  • 数ヶ月後の誰かがコードを見たとき、 「なぜこのコンポーネントが増えたのか」が理解できそうか

これらをクリアしたうえで、

  • 「この用途のために新しいコンポーネントが必要だ」と説明できる場合だけ、追加を検討する
  • 新しく作った場合は、用途・使ってよい場面を軽くコメントに残す( Figma / Notion にメモする)

という運用が理想です。

横断ルール(命名・ props ・状態)

コンポーネントごとにバラバラのルールを持たせてしまうと、使う側(実装するエンジニア)も混乱します。

そのため、次のような「横断ルール」を意識することをおすすめします。

命名のルール
  • コンポーネント名は「役割」が分かる単語にする(例:`PrimaryButton` より `Button`+`variant="primary"`)
  • 状態や見た目の違いは props(`variant`, `size`, `state` など)で表現する
共通で使う props
  • `variant`:役割・重要度(例:`primary`, `secondary`, `ghost`, `danger` など)
  • `size`:大きさ(例:`s`, `m`, `l`)
  • `disabled` / `isLoading`:状態(押せない・通信中など)
  • これらの名前は、Button だけでなく他のコンポーネントでもなるべく揃える

状態の扱い

  • hover / focus / active / disabled / error などの状態は、 コンポーネント側で一貫した見た目が出るようにしておく
  • 「この画面だけ特別な disabled の色」などはなるべく避ける

ポイント

  • 「画面側の都合でコンポーネントをねじ曲げる」のではなく、
  • 「コンポーネントのルールを増やすかどうか」を先に検討するイメージです。

代表コンポーネントごとの方針(例:Button)

以下は具体例として、Button コンポーネントについての方針をまとめたものです。

他のコンポーネント(Input / Modal など)も同じフォーマットで整理していくと、チームで使いやすくなります。

Button の役割

Button は、画面上で「ユーザーに何か行動を取ってもらうためのパーツ」です。

Dr.Tool では特に、

  • 画面のメインアクション(例:保存・登録・実行)
  • サブアクション(例:キャンセル・戻る)
  • 設定画面内の補助的な操作(例:条件追加・リセット)

など、役割の違いが多く登場します。

variant(種類)の考え方

よくあるパターンを書いておきます。

  • primary
    • その画面で一番押してほしいアクション
    • 原則として 1画面に 1つまで
  • secondary
    • メインほどではないが、よく使われる補助的なアクション
  • tertiary
    • 重要度は低いが、必要な操作(詳細表示、オプションなど)
  • danger
    • 削除やリセットなど、破壊的な操作
    • 赤系の配色で、誤操作しないように目立たせる

ルール例

  • 1画面に `primary` ボタンが複数並ばないようにする
  • 「どれが一番大事なアクションか」を決めてから variant を選ぶ

size(大きさ)の考え方

Button の size は次の軸で使い分けると分かりやすいです。

  • Large:ダイアログの主要アクションや、画面のヒーロー的なボタン
  • medium:通常のフォーム送信や主要操作
  • small:テーブル行内の操作や、補助的なアクション

使用の目安

  • 「このボタンが主役かどうか」で size を選ぶ
  • テーブルの中に 「Large」 ボタンを置くなど、文脈に合わないサイズは避ける

disabled / loading の扱い

  • disabledなボタンは、「押しても意味がない状態」を明示するために使います。
    • 例:必須項目が入力されていない、権限がない など
  • isLoadingは、通信中など「処理中で待ってほしい状態」を示すために使います。
    • スピナーアイコンの表示や、二重送信防止などをコンポーネント側で吸収できると理想的です。

他コンポーネントについて

Button 以外のコンポーネント(Input / Select / Checkbox / Modal / Table など)についても、

  • 「役割」
  • 「よくある使い方」
  • 「増やさないための決めごと」
  • 「やりがちな NG パターン」

をそれぞれ 1〜2 セクションずつでまとめていくと、チームの共通認識を揃えやすくなります。

Storybook.jsやZeroheightなどのツールを上手に活用すると、ドキュメントの管理も効率的に行う事ができます。

Buy Me a Coffee at ko-fi.com
永井 大介

© 二〇二六