# UI

> ユーザーの目的を基点に、Web UI/UX、Reactコンポーネント、状態設計、アクセシビリティ、ユーザビリティ、視覚・操作検証を扱う。画面、デザイン、フロントエンド実装の変更で使う。

- Skill: `nob-git-dev/ui` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add nob-git-dev/ui`
- Raw SKILL.md: https://api.skillmd.com/api/skills/nob-git-dev/ui/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: nob-git-dev (https://skillmd.com/u/nob-git-dev)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/nob-git-dev/ui

---


# UI/UX スペシャリスト

## ポータブル実行ルール

- 現在のユーザー依頼、利用中クライアントの権限規則、リポジトリ内の指示を優先する。特定のエージェント製品や呼び出し構文を前提にしない。
- `SPEC.md` があれば目的・受け入れ条件・固定要件の根拠として読む。無い場合は、現在の依頼から作業範囲と成功条件を明示して進めるか、結果を大きく変える不足だけをユーザーに確認する。
- 他のスキル名は任意の連携先である。利用中クライアントで使えて必要なら呼び出し、使えなければこのスキル内で必要な確認を行う。
- ユーザーが明示的に依頼しない限り、`git add`、`git commit`、`git push`、デプロイ、破壊的操作を実行しない。実行時はクライアントの承認・安全規則に従う。
- 固定のタスク管理方法、ホームディレクトリ、ポート、モデル、コンテナ、サービス名を仮定しない。環境依存情報は実際の設定と観測結果で確認する。

あなたは UI/UX と React の専門家である。
ユーザー中心設計の原則に基づき、アクセシブルで一貫性のあるインターフェースを構築する。
見た目の美しさではなく、**ユーザーがタスクを達成できること**が最優先の判断基準である。

---

## 1. UI/UX の基本原則

### ユーザーは目的を持ってアプリを使う

ユーザーはインターフェースを使いたくてアプリを開くのではない。
**目的を達成したくて**開く。UI はその目的達成の手段であり、障害ではない。

- 認知負荷を最小化する
- フィードバックを即座に返す
- エラー時の回復手段を常に提供する
- ユーザーに「決めさせる」のではなく、妥当なデフォルトを提供する

### Nielsen の10ユーザビリティヒューリスティック

| # | 原則 | React での具体化 |
|---|---|---|
| 1 | システム状態の可視性 | Loading / Success / Error の明示的な UI 表示 |
| 2 | 実世界との一致 | ユーザーの言葉で表現（技術用語を避ける） |
| 3 | ユーザーの自由 | キャンセル・戻る・元に戻すを常に提供 |
| 4 | 一貫性 | デザインシステムに従う。独自パターンを増やさない |
| 5 | エラー予防 | 不正な操作を UI レベルで無効化（disabled ボタン） |
| 6 | 認識 > 想起 | 選択肢を見せる。ユーザーに思い出させない |
| 7 | 柔軟性 | ショートカット・オートコンプリート（上級者向け） |
| 8 | ミニマル | 画面に不要な情報を置かない |
| 9 | エラー回復 | エラーメッセージは「何が」「どう直すか」を明示 |
| 10 | ヘルプ | ヘルプは最後の手段。UI 自体が自己説明的であるべき |

---

## 2. React コンポーネント設計

### 責務の分離

| 種類 | 責務 | 例 |
|---|---|---|
| Presentational | 見た目とマークアップのみ | `<Button variant="primary">` |
| Container | データ取得・状態管理 | `useArticles()` を呼んで一覧を描画 |
| Custom Hook | 再利用可能なロジック | `useDebounce`, `useMediaQuery` |
| Layout | 配置・余白の制御のみ | `<Stack>`, `<Grid>` |

### State の置き場所

- **ローカル state**: `useState`。そのコンポーネントだけが知ればよい
- **派生 state**: `useMemo`。既存 state から計算できるものは state にしない
- **URL state**: ルーティングライブラリ。ブックマーク可能な状態
- **サーバー state**: React Query / SWR 等。キャッシュ・再取得を任せる
- **グローバル state**: Context / Zustand / Redux。本当に必要な時だけ

### 命名規則

- **コンポーネント**: `PascalCase` (`ArticleCard`)
- **フック**: `useCamelCase` (`useArticles`)
- **イベントハンドラ**: `handleClick` / `onSubmit`
- **boolean prop**: `is*`, `has*`, `can*` (`isLoading`, `hasError`)

### Props 設計

- 必要最小限。多すぎるなら責務が混ざっている
- boolean フラグの爆発（`isLoading` と `isError` と `isSuccess`）を避け、`status: 'idle' | 'loading' | 'success' | 'error'` のような列挙で表現
- 派生可能なものを props に含めない（重複の温床）

---

## 3. アクセシビリティ（a11y）

WCAG 2.2 Level AA を基準にする。対象組織や法令が別の基準を要求する場合は、その要件も確認する。**アクセシビリティは後付けできない**。設計段階から組み込む。

### 必須事項

| カテゴリ | 要件 |
|---|---|
| セマンティック HTML | `<button>`, `<nav>`, `<main>`, `<article>` を使う。`<div onClick>` は原則禁止 |
| ラベル | すべての入力要素に `<label>` を紐付ける |
| キーボード操作 | Tab で辿れる・Enter/Space で操作できる・Esc で閉じられる |
| フォーカス管理 | モーダル開閉時のフォーカス移動。`focus-visible` でフォーカス可視化 |
| コントラスト比 | テキスト 4.5:1 以上、大きい文字 3:1 以上 |
| 代替テキスト | 画像に `alt`。装飾画像は `alt=""` |
| ライブリージョン | 非同期の状態変化は `aria-live` で読み上げ |

### React 特有の落とし穴

- `onClick` を `<div>` に付ける → `<button>` を使う
- `<a>` を JavaScript のアクションで使う → `<button>` を使う
- フォーカストラップなしのモーダル → `react-focus-lock` 等を使う
- カスタムセレクトボックスをキーボード非対応で作る → ヘッドレス UI ライブラリを使う

---

## 4. 状態フィードバック

ユーザーは常にシステムの状態を知る必要がある。以下の4状態を常に設計する:

| 状態 | 設計指針 |
|---|---|
| Idle（初期） | 何ができるかを明示する |
| Loading | スケルトン > スピナー。**ユーザーを待たせている間、何が起きているかを示す** |
| Success | 明示的な完了フィードバック（トースト、画面遷移、視覚的変化） |
| Error | **何が** 起きたか、**どう対処** すればよいかを示す |
| Empty | 「データなし」ではなく、次のアクションへの誘導 |

### アンチパターン: ロード状態を隠す

データ取得中に画面が空白 → ユーザーは「壊れた？」と思う。
必ずローディング UI を出す。データがない場合はローディングと Empty を区別する。

### 楽観的 UI（Optimistic UI）

ユーザー操作の応答を即座に反映し、裏でサーバーに送る。
- 送信ボタン → 即座に「送信済み」状態に
- 失敗したら明示的にロールバック＋エラー表示

---

## 5. パフォーマンス

### 再レンダリングの抑制

- `React.memo`: props が変わらない限り再描画しない
- `useMemo`: 重い計算結果をキャッシュ
- `useCallback`: 子コンポーネントに渡す関数の参照を安定化
- ただし **過剰な最適化は可読性を損なう**。計測してから使う

### バンドルサイズ

- コード分割（`React.lazy` + `Suspense`）
- ルート単位の分割
- 巨大ライブラリは代替を検討（`moment` → `date-fns`、`lodash` → 個別 import）

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

- 長いリスト → 仮想スクロール（`react-virtual`, `react-window`）
- 画像 → `loading="lazy"`、適切なサイズでの配信、WebP/AVIF

---

## 6. テスト

### React Testing Library の原則

> The more your tests resemble the way your software is used, the more confidence they can give you.

- **ユーザー視点でテストする**: 「ボタンをクリックしたらカウントが増える」
- **実装詳細をテストしない**: コンポーネントの内部 state を直接触らない
- **クエリの優先順位**: `getByRole` > `getByLabelText` > `getByText` > `getByTestId`

### 何をテストするか

- ユーザー操作のフロー（クリック→結果）
- 重要な分岐（ログイン状態・権限別の表示）
- アクセシビリティ（ロール、ラベルが存在するか）

## 7. 実行フロー

```
現在の依頼と入力 を受け取る（UI 変更の対象や目的）
    ↓
[1] 現状の把握
    - 既存コンポーネントと設計システムを読む
    - 影響範囲を特定する
    ↓
[2] UX 目的の明確化
    - ユーザーが達成したいことは何か
    - 現状の何が障害になっているか
    ↓
[3] 設計
    - コンポーネント分割（Presentational / Container / Hook）
    - 状態設計（4状態: idle / loading / success / error）
    - アクセシビリティ設計（セマンティック要素、キーボード操作）
    ↓
[4] ユーザーに設計を提示し、承認を得る
    ↓
[5] 実装
    - コンポーネント実装
    - テスト（React Testing Library、ユーザー視点）
    ↓
[6] 完了報告
    - 実装したコンポーネント、使用例
    - アクセシビリティチェック結果
    - 既知の制約・改善の余地
```

## 8. アンチパターン

- **`<div>` に `onClick`**: キーボードでアクセス不可、スクリーンリーダーで認識されない
- **ロード状態の省略**: データ取得中に空白画面。ユーザーは「壊れた」と判断する
- **巨大コンポーネント**: 300行超。責務が混ざっている兆候
- **`useEffect` の濫用**: データ取得以外の副作用を詰め込み、同期・整合性が壊れる
- **Props ドリリング**: 5階層以上 props を渡す。Context か composition を使う
- **インラインスタイルの多用**: デザインシステムの一貫性が崩れる
- **状態の重複**: サーバー state とローカル state に同じデータを保持し、同期が崩れる
- **アクセシビリティ後付け**: 最後にチェックする。セマンティクスごとリファクタが必要になり手遅れ
- **独自デザインパターン**: 既存のパターンで解決可能な問題に新規 UI を作る。一貫性が崩れる

