PackagesUIArchitecture
Elements
Primitivesを組み合わせて用途に特化したUIを提供する。
責務
Elementsは 「いつ・なぜそう見えるか」(when / why)を決める コンポーネントである。Primitivesを組み合わせ、用途に特化したAPIをアプリケーションに提供する。
- 1つ以上のPrimitivesを組み合わせ、特定の用途に最適化したAPIを提供する
- 用途に基づいた意味のあるPropsを定義する(例:
label,isLoading,icon) - 状態に応じてPrimitivesのvariant・props・表示内容を切り替える
- クライアント機能(hooks・イベントハンドラ等)を使う場合のみ
'use client'を宣言する
Elementsが決めること
| 対象 | 例 |
|---|---|
| どのvariantを使うか | isLoading が true のとき disabled を渡す |
| どのPrimitivesを組み合わせるか | Button + Spinner + Icon |
| 条件による表示切り替え | ローディング中は Spinner、通常時は Icon を表示 |
| 意味のあるProps | label, isLoading, icon など用途に基づく名前 |
| 状態の制御 | isLoading → disabled + Spinner、hasError → aria-invalid + エラーメッセージ |
Elementsが決めないこと
| 対象 | 決める層 |
|---|---|
| variant自体の見た目(色、サイズ等) | Primitives |
| hover / focus / disabled / error の見た目 | Primitives |
| 外部余白(margin) | 利用者(アプリケーション) |
| 複数Elementsの連携(フォーカストラップ等) | Composites |
| 操作前後のフロー(確認ダイアログ、Toast通知) | Composites |
責務外
Elementsが行ってはならないことを定義する。
- CVAでvariantを定義しない — スタイルのvariant管理はPrimitivesの責務である。Elementsは使用するPrimitiveのvariantを選択するだけである
- 複数の独立した機能を持たない — 1つのElementは1つの用途に対応する。フォームフィールド全体(Label + Input + Error)のように複数の関心を持つ場合はCompositeにする
- 他のElementsに依存しない — Elements同士の直接的な依存は禁止する。共通する機能はPrimitivesに切り出す(Icon は例外。依存ルールを参照)
- ビジネスロジックを持たない — バリデーションルールやAPIコール等のドメイン固有の処理は含まない
- Primitivesのvariantが担うスタイルを
classNameで上書きしない — 色・角丸・フォントサイズ等はPrimitivesのvariantで制御する。classNameはレイアウト調整(w-full,mt-4等)に限定する
要件
| 要件 | 詳細 |
|---|---|
'use client' 宣言 | hooks・イベントハンドラ・ブラウザAPIを使用する場合のみ宣言する。純粋にPropsを受けてJSXを返すだけのコンポーネントには不要 |
| 意味のあるProps | Primitiveのvariantをそのまま露出させず、用途に基づいた名前にする |
| 型安全 | すべてのPropsにユニオン型やenum型で選択肢を限定する |
| WAI-ARIA準拠 | 対応するARIAパターンが存在する場合は準拠する |
| キーボード操作 | インタラクティブな要素はキーボードで操作可能にする |
| 状態の制御 | isLoading → Primitiveに disabled を渡す、hasError → aria-invalid を渡すなど、Primitivesの状態をPropsで制御する |
| 外部余白の禁止 | margin を持たない。利用者が className で付与する |