Command Palette
Give users one keyboard-first entry point to jump anywhere and run any action without hunting through menus.
8 states7 edge casesDesktop + Mobile
01The problem
As a product grows, its navigation and menus grow with it. Experienced users know what they want — “open the Acme account”, “create an invoice”, “switch to dark mode” — but have to click through sidebars and menus to get there. A palette solves this only if it finds the right thing in a few keystrokes.
02When to use
Use when
- Products with many objects to jump between: projects, customers, documents
- Frequent actions that are buried several clicks deep
- Power users who work in the product all day
- Products that already support keyboard shortcuts
Avoid when
- The product has fewer than ~10 destinations; a clear sidebar is enough.
- Users are occasional or non-technical and won't learn the shortcut — it can't replace visible navigation.
- Only content search is needed. A search page with filters serves that better.
03Recommended UX
Statecraft recommendation
Open the palette with Cmd/Ctrl+K from anywhere, show recent items before the user types, and rank results by what the user is most likely to do — not alphabetically. Every palette action must also exist somewhere in the visible UI.
Recent items answer the most common query without typing: users mostly return to the same few places.
Ranking by intent (exact title match, then recent, then frequent, then fuzzy matches) is what makes the palette feel smart. Alphabetical lists make users read instead of act.
The palette is an accelerator, not the only way in. Hiding actions in it makes them undiscoverable for everyone who never presses Cmd+K.
04Interaction flow
- 01
Anywhere in the app
Cmd/Ctrl+K or a visible search trigger.
- 02
Palette opens
Input focused; recent items and suggested actions shown.
- 03
User types
Results update per keystroke, grouped and ranked.
- 04
Arrow to a result
Highlighted item shows its shortcut or path.
- 05
Enter
Navigate, or run the action; nested actions open a sub-step.
Result
- Navigated
- Action done
- No results
05Desktop behaviour
On desktop the palette is a centred overlay driven entirely by the keyboard. Mouse users should be able to use it too, but every interaction must work without one.
Desktop rules
- Open with Cmd/Ctrl+K; close with Escape or a click outside. Never trap the user.
- Group results by type — Recent, Pages, Customers, Actions — with groups limited to ~5 items each.
- Show each action's keyboard shortcut on its row so the palette teaches faster paths.
- Show a visible trigger in the header (“Search ⌘K”) so the feature can be discovered.
06Mobile behaviour
Phones have no Cmd key and the on-screen keyboard covers half the screen. The palette becomes a full-screen search with large targets.
Mobile rules
- Open from a search icon in the top bar; take the full screen.
- Put the input at the top and keep results scrollable above the keyboard.
- Hide keyboard shortcut hints — they're noise on touch devices.
- Use 48px rows; tapping a row runs it directly.
07States
Closed
Visible trigger in the header with the shortcut hint.
Open, empty query
Recent items and suggested actions, input focused.
Typing
Ranked, grouped results update on each keystroke; first result highlighted.
Loading remote results
Local results show immediately; server results join below without moving the highlight.
Sub-step
An action needs input, e.g. “Assign to…” lists people. Breadcrumb shows the parent action.
No results
Says what was searched and offers a fallback such as full search.
Action running
For slow actions, the palette closes and progress moves to a toast.
Action unavailable
Shown but disabled with a reason, e.g. lacking permission.
08Edge cases
EC-01
Results reorder while the user moves the highlight
The user arrows to the third result just as server results arrive and shift the list.
Recommendation
Keep the highlighted item fixed and append remote results below local ones. Pressing Enter must run what the user saw highlighted.
EC-02
Destructive actions
The user types “delete” and presses Enter on “Delete project”.
Recommendation
Never run a destructive action straight from the palette. Open the same confirmation the rest of the UI uses.
EC-03
Shortcut conflicts
Cmd+K is also the browser's or an embedded editor's link shortcut.
Recommendation
Inside rich-text editors, let the editor keep Cmd+K and offer an alternative (Cmd+P or “/”). Document both.
EC-04
Permissions
A viewer searches for “Invite member”.
Recommendation
Hide actions the user can never perform; show temporarily unavailable ones disabled with the reason.
EC-05
Stale recent items
A recent item points to a project that has since been deleted.
Recommendation
Remove it from recents on open, or mark it “Deleted” rather than letting navigation fail.
EC-06
Typos and synonyms
The user types “invioce” or “billing” when the page is called “Invoices”.
Recommendation
Use fuzzy matching and per-item keyword aliases. Synonyms are content — maintain them alongside each command.
EC-07
Large workspaces
The workspace has 50,000 customers.
Recommendation
Search locally for pages and actions, query the server for records with a short debounce, and cap each group with “Show all 312 customers”.
09Microcopy
Placeholder
Avoid
“Search…”
Prefer
“Search or jump to…”
Header trigger
Prefer
“Search ⌘K”
No results
Avoid
“Nothing found”
Prefer
“No results for “acme invoce”. Search all invoices instead?”
Disabled action
Avoid
“Unavailable”
Prefer
“Only admins can invite members”
Group overflow
Prefer
“Show all 312 customers”
10Accessibility
- Use the combobox pattern: the input has role="combobox", results form a listbox, and aria-activedescendant tracks the highlighted option.
- Focus moves to the input on open and returns to the element that opened the palette on close.
- Announce the number of results in a polite live region after typing pauses.
- Group headings must be exposed to assistive tech, not only drawn visually.
- The palette must never be the only route to a feature.
11Developer notes
- 01
Define commands in a registry (id, title, keywords, group, shortcut, permission check, run) rather than hardcoding them in the palette component.
- 02
Rank with a scoring function combining match quality, recency and frequency; store recency per user.
- 03
Load the palette code lazily on first open; it isn't needed for the initial page render.
- 04
Cancel stale remote searches when the query changes so older responses can't overwrite newer ones.
- 05
Register the global shortcut once at the app root and ignore it while a native dialog or editor has claimed the key.
12Implementation prompt
For Claude Code, Codex or Cursor
Implement a command palette for the existing application.
Requirements:
- Global Cmd/Ctrl+K opens it; Escape and outside click close it. Also add a visible "Search ⌘K" trigger in the header.
- Combobox accessibility: role="combobox" input, listbox results, aria-activedescendant, focus returned to the trigger on close.
- Empty query shows recent items and suggested actions.
- Command registry: { id, title, keywords, group, shortcut, isAvailable(user), run }.
- Results grouped (Recent, Pages, Records, Actions), max ~5 per group with "Show all N".
- Ranking: exact/prefix title match > recent > frequent > fuzzy; support keyword aliases.
- Local results instantly; remote record search debounced, appended below, never moving the highlighted item.
- Show shortcuts on action rows (desktop only).
- Destructive actions open the standard confirmation instead of running directly.
- Hide actions the user can never perform; show temporarily unavailable ones disabled with a reason.
- No-results state names the query and offers full search.
- Mobile: full-screen search from a top-bar icon, 48px rows, no shortcut hints.
- Lazy-load the palette on first open.
Do not redesign the existing interface.
Keep commands and ranking logic separate from the palette UI.