mcpField
U
ui-engineering

ui-engineering

github.com/noobygains開発11559 回インストール3 日前に更新
リポジトリ

ui-engineering について

ui-engineeringは、フロントエンドコンポーネントを構築する開発者向けの実践スキルです。実装前に、構造や状態、アクセシビリティ、レスポンシブ設計、フォーム、パフォーマンスを検討する指針を示します。

主な機能

  1. 01コンポーネント構成と設計の確認
  2. 02GridとFlexboxの選択指針
  3. 03状態の配置原則
  4. 04レスポンシブ設計の手法
  5. 05アクセシビリティとフォームの基準
  6. 06モーションと描画性能の指針

活用シーン

  1. 01コーディング前の構造と状態の設計
  2. 02ページレイアウト方式の選定
  3. 03レスポンシブなフォームやナビゲーションの構築
  4. 04インタラクティブ要素のアクセシビリティ確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/noobygains/godmode --skill ui-engineering

インストール後、Claude Code で/ui-engineeringを入力して読み込まれたか確認します。

同梱ファイルcomponent-patterns.md

詳細

UI エンジニアリング

概要

場当たり的なマークアップではなく、規律あるアーキテクチャで UI コンポーネントを構築します。

基本原則: レイアウト戦略、状態の所有者、アクセシビリティへの配慮、レスポンシブな動作など、すべてのコンポーネントに関する判断は、確立されたパターンに従います。UX Patterns スキルは、何を構築するかを示します。このスキルは、構造的な整合性を保ちながら、どのように構築するかを示します。

前提条件: まず godmode:ux-patterns を呼び出して、適用するパターンとトークン値を特定してください。このスキルでは、トークンとパターンがすでに確立されていることを前提としています。

使用する場面

必須となる場合:

  • フロントエンドコンポーネントを構築するとき
  • Grid と Flexbox のどちらを使うか選択するとき
  • 状態をどこに保持するか決めるとき
  • レスポンシブなブレークポイントの動作を設計するとき
  • フォーム、データ可視化、ナビゲーション、オーバーレイを構築するとき
  • モーションやトランジションを導入するとき

次の工程として実施:

  • デザイントークンが確立された後(ux-patterns)
  • 対象となる UI パターンが特定された後(ux-patterns)

最優先指針

NO COMPONENT WITHOUT STRUCTURE, STATES, AND ACCESSIBILITY DEFINED FIRST

コンポーネントのコードを書く前に、セマンティックな構造(適切な HTML 要素)、すべての視覚状態(空、読み込み中、エラー、データあり、無効)、アクセシビリティ要件(ARIA 属性、キーボード操作、コントラスト比)を確立します。

コンポーネントのアーキテクチャ

設定より合成

巨大でプロパティが多いブロックではなく、小さく合成可能な単位からコンポーネントを組み立てます。

``` Dialog DialogHeader DialogTitle DialogDescription DialogBody DialogFooter ``` それぞれの単位は単独で利用でき、独立してスタイルを設定できます。 ``` Dialog (title, description, body, footer, headerAlign, footerAlign, showCloseButton, variant, size, overlayOpacity, titleSize, ...) ``` プロパティが肥大化し、保守が困難で、拡張もできません。
実装前チェックリスト

コンポーネントを書く前に、以下を確認します。

  1. セマンティクス -- 適切な HTML 要素は何ですか?(div onClick ではなく button、div className="nav" ではなく nav)
  2. プロパティ -- 必要最小限のインターフェースは何ですか?設定するのではなく、合成できますか?
  3. 状態 -- デフォルト、ホバー、フォーカス、アクティブ、無効、読み込み中、エラー、空
  4. バリエーション -- どのような視覚的なバリエーションが必要ですか?(primary、secondary、ghost、destructive)
  5. サイズ -- サイズの段階は何種類ありますか?(sm、md、lg -- 最大 3~4 種類)
  6. レスポンシブ対応 -- 各ブレークポイントでどのように変化しますか?
  7. アクセシビリティ -- ARIA ロール、キーボードナビゲーションの経路、スクリーンリーダーへの通知

レイアウト戦略の選択

digraph layout_choice {
    rankdir=TB;
    q1 [label="What is being\narranged?", shape=diamond];
    q2 [label="Single axis or\ntwo axes?", shape=diamond];
    q3 [label="Are items\nuniform in size?", shape=diamond];

    grid [label="Use CSS Grid\ngrid-template-columns\ngrid-template-rows", shape=box];
    flex [label="Use Flexbox\nflex-direction\njustify/align", shape=box];
    grid_auto [label="Use CSS Grid\nauto-fill/auto-fit\nminmax()", shape=box];

    q1 -> q2;
    q2 -> grid [label="two axes\n(rows AND columns)"];
    q2 -> q3 [label="single axis\n(row OR column)"];
    q3 -> grid_auto [label="yes\n(uniform cards)"];
    q3 -> flex [label="no\n(nav items,\nform row)"];
}
CSS Grid -- 適切な場面
  • ページレベルの骨組み(サイドバー+メインコンテンツ+補助領域)
  • 均一なカードグリッド
  • ダッシュボードの配置(メトリックタイル、チャート領域)
  • 2 次元の制御が必要なレイアウト
  • 行と列をまたいだ配置

パターンの例:

/* Self-adjusting card grid */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: var(--space-6);
}

/* Dashboard scaffold */
.dashboard {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  grid-template-rows: auto 1fr;
  gap: var(--space-6);
}
.dashboard .wide-chart { grid-column: span 2; }
Flexbox -- 適切な場面
  • 1 行に並ぶナビゲーション項目
  • フォーム入力とボタンを横並びにするグループ
  • コンテナー内でコンテンツを中央揃えにする
  • 1 つの軸に沿って幅が異なる項目を配置する

パターンの例:

/* Navigation row */
.nav-row {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

/* Inline form group */
.inline-group {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
}
.inline-group .input-field { flex: 1; }

状態の所有者を決める戦略

digraph state_ownership {
    rankdir=TB;
    q1 [label="Where does this\nstate belong?", shape=diamond];
    q2 [label="Consumed by\nmultiple components?", shape=diamond];
    q3 [label="Server-originated\nor client-only?", shape=diamond];
    q4 [label="Prop-drilling\nexceeds 3 levels?", shape=diamond];

    local [label="Component-local state\nuseState / ref", shape=box];
    server [label="Server state manager\nTanStack Query / SWR", shape=box];
    context [label="Context / Provider\nReact Context / provide-inject", shape=box];
    global [label="Global store\nZustand / Pinia / Signals", shape=box];

    q1 -> q2;
    q2 -> local [label="no\n(isolated component)"];
    q2 -> q3 [label="yes"];
    q3 -> server [label="server-originated\n(API responses,\ncached data)"];
    q3 -> q4 [label="client-only\n(UI flags,\npreferences)"];
    q4 -> context [label="no\n(2-3 levels)"];
    q4 -> global [label="yes\n(application-wide)"];
}

基本原則:

  1. ローカル状態から始めます。根拠がある場合にのみ、より上位へ移します。
  2. サーバーデータはクライアント状態ではありません。専用のサーバー状態管理ライブラリを使って管理します。
  3. コンテキストは依存性注入(テーマ、認証コンテキスト)のために使い、高頻度の更新には使いません。
  4. グローバルストアは最後の手段であり、出発点ではありません。

レスポンシブデザインの手法

モバイルファーストで段階的に対応

モバイル向けのスタイルをベースラインとして記述し、画面幅の広いブレークポイントで段階的に複雑さを加えます。

/* Mobile baseline */
.wrapper {
  padding: var(--space-4);
}

/* Tablet tier */
@media (min-width: 768px) {
  .wrapper {
    padding: var(--space-6);
    max-width: 768px;
    margin: 0 auto;
  }
}

/* Desktop tier */
@media (min-width: 1024px) {
  .wrapper {
    padding: var(--space-8);
    max-width: 1280px;
  }
}
レスポンシブ対応の参考
要素モバイルタブレットデスクトップ
ナビゲーションハンバーガーメニューまたはボトムシートタブバーまたは折りたたみ式サイドバー展開されたサイドバー
カードグリッド1列2列3~4列
データテーブルカード形式で縦に表示、または横スクロール列数を減らした全テーブル完全なテーブル
サイドバー + メインメインのみ。サイドバーはドロワー内アイコンのみのサイドバー完全に展開されたサイドバー
フォーム1列、入力欄は幅いっぱいに広げる1列、最大幅 560px関連するフィールドを2列で表示
モーダル全画面シートビューポート幅の80%で中央に配置最大幅 480px で中央に配置
ヒーロー縦に配置(見出しの下に画像)縦に配置、文字を大きくする横に並べて配置

アクセシビリティ基準

すべてのインタラクティブ要素
  • Tab キーで移動できる
  • フォーカスリングが見える(:focus-visible、アウトラインは最低2px)
  • Enter/Space(ボタン)または Enter(リンク)で有効化できる
  • アクセシブルな名前がある(表示テキスト、aria-label、または aria-labelledby)
  • 無効状態ではタブ順から除外するか、aria-disabled を適用する
  • モバイルではタッチターゲットが最小 44x44px を満たす
フォーム
  • すべての入力欄に表示される <label> がある(プレースホルダーだけでは不十分)
  • 必須フィールドを示す(アスタリスクと aria-required="true")
  • エラーメッセージが入力欄に関連付けられている(aria-describedby)
  • エラーは色だけでなく、アイコンとテキストを併用して示す
  • 送信結果をスクリーンリーダーに通知する(aria-live)
画像とアイコン
  • 意味のある画像には説明的な alt テキストを設定する
  • 装飾用画像には alt="" または aria-hidden="true" を設定する
  • アイコンのみのボタンには aria-label を設定する
  • SVG アイコンには role="img" と aria-label、または aria-hidden="true" を設定する
色とコントラスト
  • 通常のテキストはコントラスト比 4.5:1 を満たす(大きなテキストは 3:1:太字で18px以上、または24px以上)
  • 情報を色だけで伝えない(アイコン、パターン、テキストを併用する)
  • モーションは prefers-reduced-motion に従う
  • ダークモードを提供する場合、配色は prefers-color-scheme に従う

アニメーションとモーション

アニメーションを使う場面
  • 状態遷移: ホバー、フォーカス、展開/折りたたみ、表示/非表示
  • フィードバック: 成功、エラー、読み込みの進行状況
  • 空間的な手がかり: コンテンツの表示元や消えた場所を伝える
アニメーションを使わない場面
  • 機能的な目的のない装飾
  • UI 遷移の継続時間が 300ms を超える場合
  • ユーザー操作を妨げるモーション(強制的な待機)
  • ユーザーが制御できない連続的な動き
タイミングの参考
インタラクション継続時間イージング
ホバー時の反応150msease
ボタン押下100msease-out
モーダルの表示200msease-out
モーダルの終了150msease-in
ドロワーのスライド250msease-out
フェードイン200msease
ページ遷移200-300msease-in-out
ユーザーのモーション設定に従う
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

フォームの設計

バリデーションの使いやすさ
  1. キー入力のたびにバリデーションしないでください。 フォーカスが外れたとき(フィールドを離れたとき)またはフォーム送信時に検証します。
  2. エラーは該当するフィールドの下にインラインで表示し、 サマリーバナーには表示しません。
  3. エラーのテキストで補助テキストを置き換えます。 両方を同時に表示しないでください。
  4. エラーは色とアイコンを併用して示し、 色だけで示さないでください(アクセシビリティ)。
  5. ユーザーの入力に応じて、入力内容が有効なフィールドの表示(チェックマークまたは緑色の枠線)を維持します。
  6. 送信中は送信ボタンを無効にし、読み込みインジケーターを表示します。
フィールド配置のガイドライン
  • ラベルは入力欄の上に配置する(横に並べない。プレースホルダーだけにしない)
  • 関連するフィールドは <fieldset> と <legend> でまとめる
  • 必須フィールドにはアスタリスクと (required) の両方を付け、スクリーンリーダーに伝える
  • 任意のフィールドには代わりに「(optional)」を表示してもよい
  • フォームの最大幅:1列の場合は 480-560px
  • 送信ボタンは中央ではなく左揃えにする(モーダル内を除く)

レンダリングのパフォーマンス

クリティカルパスの最適化
  1. ファーストビューのコンテンツを最初に読み込みます。 ファーストビューより下にあるアセットとスクリプトは遅延させます。
  2. ブランディング上、Web フォントが必須でない限り、本文にはシステムフォントを優先します。 Web フォントはレイアウトシフトを引き起こします。
  3. 画像の適切な扱い: width/height 属性を指定して(CLS を防止)、ファーストビューより下の画像には loading="lazy" を設定し、レスポンシブな配信には srcset を使用します。
  4. バンドルを意識します: インポートするライブラリはすべてコストになります。依存関係を追加する前に、バンドルへの影響を測定します。
遅延読み込み戦略
  • ファーストビューより下の画像:loading="lazy"
  • ルートモジュール:動的インポート/コード分割
  • 重いコンポーネント(チャート、リッチエディター):操作時または表示時に読み込みます
  • ファーストビューのコンテンツは遅延読み込みしないでください

よくある間違い

間違い修正方法
すべてに div を使うセマンティック HTML(button、nav、main、section、article)を使用します
プレースホルダーだけをラベルとして使う常に表示される <label> 要素を用意します
あらゆる場所にピクセル値を直書きするデザインシステムのトークン変数を使用します
コンテナーの幅を固定するmax-width とパーセンテージ、または自動マージンを使用します
フォーカスのアウトラインを削除するアウトラインをなくすのではなく、:focus-visible をスタイル設定します
div にクリックハンドラーを設定するインタラクティブな要素には <button> または <a> を使用します
レイアウトの間隔にマージンを使うGrid または Flexbox で gap を使用します
アイコンライブラリ全体をインポートする個々のアイコンをインポートし、ツリーシェイキングを有効にします
ハッピーパスだけを実装するハッピーパスを構築する前に、すべての状態を設計します
デスクトップでしかテストしないモバイルファーストでテストし、その後デスクトップで確認します

統合

前提条件:

  • godmode:ux-patterns -- 最初にトークンとパターンを確立する必要があります

補完スキル:

  • godmode:design-integration -- 確立済みのデザインシステム内で作業する場合
  • godmode:test-first -- コンポーネントテストはテストファーストの手法に従います

サポートファイル:

  • component-patterns.md -- アクセシビリティを組み込んだ再利用可能なコンポーネントの設計図

コメント