⌘K(Mac)/ Ctrl+K(Windows)で呼び出す、アプリ全体のコマンド・ページ・設定を横断検索して即時実行できるUIコンポーネント。VS Code・Linear・Vercelが採用して広まった、パワーユーザーの作業効率を飛躍的に高める「キーボードファースト」のUI。
この記事を読むと、Command PaletteとSearchの設計上の違い・combobox ARIAパターンの実装・グループ分けと最近使ったコマンドの設計・⌘K のフォーカストラップとEscape の実装が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
アプリケーション全体のコマンド・ページ・設定を横断して検索・実行できるモーダル型UIコンポーネント。⌘K(Mac)/ Ctrl+K(Windows)で呼び出し、キーボードだけですべての操作を完結させる。VS Code・Linear・Notion・Vercelなどが採用してパワーユーザー向けUIの標準パターンになった。
SearchとCommand Paletteの違い:Searchは「コンテンツ(記事・商品)を探す」。Command Paletteは「アプリの機能・コマンド・ページへの遷移」を実行する。検索結果が「情報」か「アクション」かが根本的な違い。
Dropdownとの違い:DropdownはコンテキストメニューやSelect的な「限定された選択肢の列挙」。Command Paletteはフリーテキストでアプリのあらゆるコマンドをインクリメンタルに絞り込む「全機能への入口」。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- 機能が多く、メニュー階層が深いアプリ(設定項目が多いSaaS・IDE・デザインツール)
- パワーユーザーが多いプロダクト(開発者ツール・管理画面)
- ナビゲーション階層を何度もクリックしなければ到達できない機能へのショートカットとして
- 「この機能どこにあったっけ?」という体験をなくしたい場合
3.2 When NOT to use
- シンプルなコンシューマー向けアプリ → 複雑すぎてかえって混乱する
- 機能が10個以下のシンプルなアプリ → 通常のナビゲーションで十分
- キーボード操作に慣れていないユーザーが主なターゲット
3.3 代替UI(Alternatives)
- コンテンツ検索 →
Search(検索) - 限定的なアクション選択 →
Dropdown Menu - ページナビゲーション →
Sidebar・Menubar
4. 設計判断の核(Decision Principles)
Command Paletteの核はキーボード操作の完全性——マウスなしで「開く→検索→実行→閉じる」が完結しないCommand Paletteはパワーユーザーの信頼を失う。
判断の優先順位:① キーボード操作(↑↓Enter Esc)→ ② フォーカストラップ → ③ グループ分け → ④ 最近使ったコマンド
- ↑↓ Enter Esc はすべて実装必須:Command Paletteを使うユーザーはキーボードで操作する前提。矢印キーでリストを移動、Enterで実行、Escで閉じる——この4キーが機能しないと使い物にならない
- フォーカストラップを必ず実装:パレットが開いている間はTabフォーカスをパレット内に閉じ込める。背後のコンテンツをキーボードで操作できてしまうと混乱する
- グループ分けで認知負荷を下げる:「最近使ったコマンド」「ページへ移動」「アクション」などグループに分けて表示する。入力なし時は最近使ったものを上位に表示する
- フッターにキーボード操作ヒントを表示:
↑↓で移動↵で実行Escで閉じるを小さく表示して発見可能性を高める
5. 状態設計(States)
5.1 必須状態(Required)
- Closed(閉じた状態):
⌘Kトリガーボタンのみ表示 - Open(空の検索):最近使ったコマンド / よく使うコマンドをデフォルト表示
- Searching(入力中):インクリメンタルにコマンドをフィルタリング
- Empty(0件):一致するコマンドなし
5.2 条件付き状態(Conditional)
- Selected(選択中):↑↓キーで移動中のアイテムをハイライト
- Loading:サーバーサイドコマンド取得中
5.3 State Gallery
| 状態 | 必須 | 何を伝えるか |
|---|---|---|
| Closed | ✅ | ⌘K で開けることを示す |
| Open(デフォルト) | ✅ | 最近使ったコマンドを提示 |
| Searching | ✅ | インクリメンタルな絞り込み |
| Empty(0件) | ✅ | 一致なし+代替を示す |
| Selected | ✅ | ↑↓で選択中のコマンド |
6. バリエーション設計(Variants)
Command Paletteはほぼ単一パターン。差が出るのはコンテンツのグループ構成。
| バリアント | 内容 | 適したプロダクト |
|---|---|---|
| コマンドのみ | アクション・設定変更のみ | VSCode・IDE系 |
| コマンド+ページ移動 | コマンド+ページへのリンク | SaaS管理画面 |
| コマンド+検索統合 | コンテンツ検索も統合 | Notion・Linear |
禁止パターン:Command Paletteをマウスのみで使えるように設計する(キーボード操作を後付けにする)→ Command Paletteはキーボードファーストで設計し、マウスをセカンダリサポートとして扱う。
7. パターン集(Good / Bad / How to fix)
7.0 よく崩れる設計パターン(3つ)
- フォーカストラップなし:Command Paletteが開いているのに、Tabキーで背後のナビゲーションリンクにフォーカスが移ってしまう
- Escで閉じた後のフォーカス喪失:Escで閉じた後、フォーカスがどこにも当たらず、次の操作でTabを何度押しても意図した場所に行けない
- コマンドをグループ分けしない:すべてのコマンドがフラットに並び、入力なしの状態で何を実行すべきか判断できない
7.1 Bad(典型3つ)
onKeyDownにArrowDown・ArrowUp・Enter・Escapeの処理がなく、マウスでしか操作できない- パレットを閉じた後
document.bodyにフォーカスが当たり、次のTabキーで意図しない場所にジャンプする - 入力なし時にすべてのコマンドがアルファベット順でフラットに並び、どこから始めればいいか分からない
7.2 Good(対になる3つ)
onKeyDownでArrowDown・ArrowUp(インデックス移動)・Enter(実行)・Escape(閉じる)を完全に実装するonClose時にtriggerRef.current?.focus()で⌘Kを押したトリガーボタンにフォーカスを戻す- 入力なし時は「最近使ったコマンド」グループを上位3〜5件表示し、よく使う操作への素早いアクセスを提供する
7.3 How to fix(手順)
useRefで⌘Kトリガーボタンの参照を保持し、onClose時にfocus()を呼ぶuseEffect+tabIndex="-1"とonKeyDownでフォーカストラップを実装する(またはfocus-trap-reactライブラリを使う)- コマンドリストに
role="listbox"+ グループにrole="group"を付与する localStorageに最近実行したコマンドを保存して、入力なし時のデフォルト表示に使う
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Keyboard
⌘K/Ctrl+Kでパレットを開くTab/Shift+Tabでパレット内のフォーカス移動(フォーカストラップ)↑・↓でコマンドリスト内を移動Enterで選択中コマンドを実行Escapeでパレットを閉じ、トリガーにフォーカスを戻す
Focus
- パレットが開いたら即座に検索入力にフォーカスする(
autoFocus) - フォーカストラップ:パレット外にフォーカスが出ないようにする
- 閉じた後:
⌘Kを押した要素にフォーカスを戻す
Screen Reader
<div
role="dialog"
aria-modal="true"
aria-label="コマンドパレット"
>
<input
role="combobox"
aria-expanded="true"
aria-controls="command-listbox"
aria-autocomplete="list"
aria-activedescendant="cmd-3"
/>
<ul id="command-listbox" role="listbox">
<li role="group" aria-label="最近使ったコマンド">
<ul>
<li id="cmd-1" role="option" aria-selected="false">ダッシュボードを開く</li>
<li id="cmd-2" role="option" aria-selected="false">新しい記事を作成</li>
</ul>
</li>
</ul>
</div>
Touch / Pointer
- モバイルでは
⌘Kショートカットが機能しないため、ナビゲーションに検索ボタンを常設してタップで開けるようにする - コマンドアイテムのタップ領域は最低44pxを確保する
Contrast / Readability
- 選択中アイテムの背景と文字のコントラストは4.5:1以上
- グループラベルと通常テキストのサイズ差・色差を明確にする
10. 実装メモ(Implementation Notes)
- shadcn/ui の
Commandコンポーネントは完全な combobox ARIAパターン・キーボードナビゲーション・グループ分けが実装済み。cmdkライブラリがベース。新規実装よりCommandを使うのが最速 - フォーカストラップは
focus-trap-reactパッケージが最も確実。自前実装する場合はfocusableセレクタで全フォーカス可能要素を取得してTabキーをインターセプトする ⌘KのグローバルキーバインドはuseEffectのwindow.addEventListener('keydown', ...)で実装し、return () => removeEventListenerでクリーンアップする- Next.js App Router では
useRouter().push()でコマンドからページ遷移できる。router.pushはコンポーネントのアンマウント前に呼べるため、パレットを閉じる前に遷移できる
11. 関連リンク
- 関連するUIデザイン原則: スキャンしやすさ (Scannability), フィードバック (Feedback), 段階的開示 (Progressive Disclosure)
- 用語集(定義): アクセシビリティ (Accessibility)
- 関連するUIコンポーネント(横): Search(検索), Dropdown Menu(ドロップダウンメニュー), Modal / Dialog(モーダル)
12. まとめ
Command Paletteの設計はキーボード操作の完全性が第一です。迷ったら 4. 設計判断の核 に戻り、↑↓Enter Esc の実装・フォーカストラップ・Esc後のフォーカス戻しの3点を確認してください。shadcn/ui の Command コンポーネントはこれらをすべて実装済みのため、一から実装する前に必ず検討してください。「パワーユーザーが毎日使うUI」として設計することが、Command Palette品質の基準です。