---
title: Command Palette
slug: command-palette
kind: pattern
summary: One keyboard-summoned box that searches records and actions together, so an expert reaches anything in the product without navigating to it.
problem: >-
  Someone who uses the product all day knows exactly what they want and still
  has to travel — click a section, filter a list, find a row, open a menu. The
  navigation was built for people learning the app, and they stopped learning it
  months ago.
family: [find, act]
data_shape: [app, collection]
principles: [friction, surface-dont-bury]
interaction: [navigation, search]
density: low
complexity: medium
status: stable
visibility: public
use_when:
  - People use the product daily and know what they want before they look for it.
  - There are more destinations and actions than a navigation bar can honestly hold.
  - Records have names people remember and would type.
avoid_when:
  - The product is used occasionally. A palette rewards memory nobody has built.
  - It would become the only route to something. A palette is an accelerator, never the sole path.
  - The app has six screens, where navigation is already faster than typing.
alternatives:
  - slug: persistent-navigation
    when: People are still learning the product and need to see what exists.
  - slug: global-search
    when: People want to find records, not run actions, and expect a results page.
ask_leo: |
  Add a command palette to this app.

  - Open it with Cmd+K and Ctrl+K from anywhere, and give it a visible entry
    point too — a search affordance in the header showing the shortcut — so
    people who never learn the key can still find it.
  - Search records AND actions in one list, grouped with headings, so someone
    who types "invoice" sees both matching invoices and "Create invoice".
  - Rank by what the person used recently, then by match quality. Show something
    useful when the box is empty: recent records and the most common actions.
  - The whole thing works from the keyboard: arrows to move, Enter to run, Escape
    to close, and focus returns to where it was.
  - Show the matched text in each result so it is obvious why a row is there.
  - Never make the palette the only way to reach something. It is an accelerator
    on top of real navigation, not a replacement for it.
related:
  - title: Cmd+K Global Search
    url: /cookbook/global-search-command-palette
    summary: The implementation — the Rails and Stimulus version of this pattern.
  - title: Surface, don't bury
    url: /patterns/surface-dont-bury
    summary: Why a palette does not excuse a badly ranked navigation bar.
---

## Anatomy

```
┌──────────────────────────────────────────────────┐
│ ⌘K  invoi|                                       │
├──────────────────────────────────────────────────┤
│ ACTIONS                                          │
│   ⌁ Create invoice                               │
│   ⌁ Export invoices as CSV                       │
│ INVOICES                                         │
│ ▸ INV-1041  Riverside Fit-Out      overdue       │
│   INV-1043  Kestrel Joinery        overdue       │
├──────────────────────────────────────────────────┤
│ ↑↓ move   ↵ open   esc close                     │
└──────────────────────────────────────────────────┘
```

Four things separate a palette from a search box:

1. **Actions and records in one list.** "Invoice" is both a noun and a job. A
   palette that only finds nouns sends people back to a menu for the verb.
2. **A useful empty state.** Before typing, show recents and common actions.
   This is what teaches people the palette is worth opening.
3. **Complete keyboard control**, including returning focus on close.
4. **A visible entry point.** The shortcut is for people who know it; the
   affordance in the header is how anyone becomes one of those people.

## Why it works

It decouples reach from structure. Navigation depth is a compromise between
what is frequent and what exists; a palette makes that compromise irrelevant for
anyone willing to type, because everything is one keystroke away regardless of
where it lives.

That is why it is filed under both [find](/patterns/families/find) and act. Its
real subject is not searching — it is collapsing "get to the thing" and "do the
thing" into a single gesture.

## The failure it invites

**A palette is not a fix for bad navigation.** It is easy to add one and stop
ranking the nav bar, because the people who complain loudest are the experts and
they now have their accelerator. Everyone else — new hires, occasional users,
anyone in their first month — is left with the structure you gave up on.

Watch for the palette becoming the only route to a feature. That is the point at
which it stopped being an accelerator and became a hiding place.

## Getting it wrong

- **Results with no explanation.** If it is not obvious why a row matched,
  people stop trusting the ranking and go back to the menu.
- **Ranking by relevance only**, ignoring recency. What someone touched an hour
  ago is almost always what they want now.
- **No visible entry point**, so only people told about it ever use it.
- **Trapping focus on close**, which is a small thing that makes the whole
  feature feel unfinished.

## Exemplars

**Linear** is the reference implementation: records, actions, navigation and
settings in one ranked list, and the product is genuinely faster to drive from
the palette than from its own sidebar.

**VS Code** shows the ceiling and the risk in the same product. Its palette
exposes every command, which makes it enormously powerful and also means many
features have no discoverable home outside it.

**Slack** demonstrates the ranking point: the empty state is recent
conversations, which is right almost every time, so opening the palette is
usually already the answer.

The extractable rule: **a palette rewards memory, so it must be built on
recency.** Match quality alone treats every session as the first one.
