UIXHERO

Command Palette(コマンドパレット)

キーボードショートカット(⌘K / Ctrl+K)で呼び出す全機能横断の検索・実行UIコンポーネント。アプリ内のコマンド・ページ・設定を横断検索し、キーボードだけで操作を完結させるパワーユーザー向けUI設計を解説する。

2026年3月2日
更新: 2026年9月14日
約22分
by Dengen Yosho(DGYS)

⌘K(Mac)/ Ctrl+K(Windows)で呼び出す、アプリ全体のコマンド・ページ・設定を横断検索して即時実行できるコンポーネント。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・E・デザインツール)
  • パワーユーザーが多いプロダクト(開発者ツール・管理画面)
  • 階層を何度もクリックしなければ到達できない機能へのショートカットとして
  • 「この機能どこにあったっけ?」という体験をなくしたい場合

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:サーバーサイドコマンド取得中
状態必須何を伝えるか
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(手順)

  1. useRef で ⌘K トリガーボタンの参照を保持し、onClose 時に focus() を呼ぶ
  2. useEffect + tabIndex="-1" と onKeyDown でフォーカストラップを実装する(または focus-trap-react ライブラリを使う)
  3. コマンドリストに role="listbox" + グループに role="group" を付与する
  4. 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 ARパターン・キーボードナビゲーション・グループ分けが実装済み。cmdk ライブラリがベース。新規実装より Command を使うのが最速
  • フォーカストラップは focus-trap-react パッケージが最も確実。自前実装する場合は focusable セレクタで全フォーカス可能要素を取得してTabキーをインターセプトする
  • ⌘K のグローバルキーバインドは useEffect の window.addEventListener('keydown', ...) で実装し、return () => removeEventListener でクリーンアップする
  • Next.js App Router では useRouter().push() でコマンドからページ遷移できる。router.push はコンポーネントのアンマウント前に呼べるため、パレットを閉じる前に遷移できる

11. 関連リンク


12. まとめ

Command Paletteの設計はキーボード操作の完全性が第一です。迷ったら 4. 設計判断の核 に戻り、↑↓Enter Esc の実装・フォーカストラップ・Esc後のフォーカス戻しの3点を確認してください。shadcn/ui の Command コンポーネントはこれらをすべて実装済みのため、一から実装する前に必ず検討してください。「パワーユーザーが毎日使うUI」として設計することが、Command Palette品質の基準です。

更新のお知らせ

サイトに載せていない実例や、新しい記事のお知らせはこちらで出しています。

読んだ内容を、自分の画面に当てるとき

UIXHEROは、記事を書くほかに、画面の検品・判定、デザインシステムの構築、実装と改善の伴走を受けています。何を頼めばいいか決まっていない段階の相談も、同じ窓口で受けます。

UIXHEROに頼めることを見る

※ 記事の内容についての質問や、書いてほしいテーマの要望も同じ窓口で受けています

記事をシェア

メールでお知らせを受け取る

最終更新: 2026年9月14日

この記事を書いた人

Dengen Yosho(DGYS)

Dengen Yosho(DGYS)

UI/UXデザイナー兼デザインエンジニア デザイン歴25年以上 情報設計〜UIデザイン〜React/TypeScriptによる実装までを一気通貫で担当 大手企業のDXプロジェクトや決済アプリ領域で、デザインリードとして改善と構築を経験 現在はフリーランスとして、プロダクトのUI/UX改善とデザインシステム構築を支援 長年の実務の中で感じてきたのは、 「良いUI」はセンスではなく、再現可能な判断の積み重ねであるということ UIXHEROは、 心理学や行動科学の知見を、現場で使える設計言語に翻訳するための場所 関心領域は「ユーザーの行動が変わるUI」 人の認知・注意・意思決定の構造を理解し、 “なぜそのUIが機能するのか”を言語化することを目指している

あわせて読みたい

この記事に関連する記事をご紹介します

Day Band(いちにちの帯)

1日を1本の帯にして、時間帯を面で、節目を印で、いまの時刻とつまみを重ねて見せるUIコンポーネント。器が1日に固定されることの意味、4つの層の重ね方、印のラベルと時刻の数字を分ける理由、触った瞬間に動かさない理由を解説する。

2026年9月14日
約24分

Live Badge(LIVEの札)

隣の数字がいまの値かどうかを示す小さな札。状態を表す語を枠で囲って独立させる理由、明滅と色を補助に留める理由、実時間から外れたときに「古い」ではなく「いつの値か」を出す設計判断とARIA実装を解説する。

2026年9月14日
約21分

Time Transport(時間の操作盤)

いま映している時刻を、名前をつけた速さの段で動かし、決まった幅で飛ばし、ひと押しで「いま」へ戻すための操作盤。速さを連続値にしない理由、向きをアイコンに持たせる理由、状態を大きい表示の色で示さない理由を解説する。

2026年9月14日
約25分

もっと深く知りたいですか?

ここに掲載されていないトピックについても、リクエストがあれば解説記事を追加します。 わかりにくい点や、具体的な事例について知りたいことがあれば教えてください。

リクエストを送る