CommandPalette component
CommandPalette is the ⌘K overlay — a search box over a fuzzy-filtered, grouped list of actions and destinations, with full keyboard navigation. The useCommandPalette hook wires up the hotkey and open state.
Playground
Change a prop on the right and the preview updates. Switch to Code to copy what you see.
Recipes
Copy-paste patterns for the ways CommandPalette actually gets used — each one a real, self-contained example.
⌘K command menu
useCommandPalette wires up the ⌘/Ctrl+K hotkey and open state; spread getPaletteProps() onto CommandPalette. Items are grouped and fuzzy-filtered as you type.
const palette = useCommandPalette();
<Button variant="bordered" onPress={palette.open}>
Search… (⌘K)
</Button>
<CommandPalette
{...palette.getPaletteProps()}
items={items}
onSelect={(item) => run(item.id)}
/>Grouped items with shortcuts
Each item carries a label, a group, optional icon, shortcut, description, and keywords for fuzzy matching beyond the visible label.
const items = [
{ id: "new", label: "Create invoice", group: "Actions", shortcut: ["⌘", "N"] },
{ id: "export", label: "Export CSV", group: "Actions", description: "Downloads the current view" },
{ id: "dashboard", label: "Go to dashboard", group: "Navigation", keywords: ["home"] },
{ id: "settings", label: "Open settings", group: "Navigation" },
];Controlled open state
Skip the hook and drive it directly with isOpen/onClose when something other than the hotkey opens it — a toolbar button, a first-run tour.
const [open, setOpen] = useState(false);
<Button variant="bordered" onPress={() => setOpen(true)}>
Open palette
</Button>
<CommandPalette
isOpen={open}
onClose={() => setOpen(false)}
items={items}
onSelect={(item) => run(item.id)}
/>Example
const { open, getPaletteProps } = useCommandPalette({ hotkey: "mod+k" });
<CommandPalette
{...getPaletteProps()}
items={commandItems}
placeholder="Search…"
/>Props
The full public API for CommandPalette. Every prop is stable and intentionally typed.
Behavior & states
| Prop | Type | Default | Description |
|---|---|---|---|
| isOpen | boolean | — | Whether the palette is shown. |
| onClose | () => void | — | Fired on Escape, outside click, and after a selection. |
| onSelect | (item) => void | — | Fired on activation, after the item's own onSelect. |
| filter | (items, query) => items | built-in fuzzy | Replace the matcher; return the items to show, already ordered. |
| isLoading | boolean | false | Spinner in the input; suppresses the empty message. |
| onQueryChange | (query) => void | — | Fired as the query changes. |
| closeOnEscape / closeOnOutsideClick / portal / container / zIndex / blur | — | — | Passed through to Backdrop. |
| hotkey | "mod+k" | string | false | "mod+k" | Global open/toggle shortcut. mod = ⌘ on Apple platforms, Ctrl elsewhere. false binds nothing. |
| defaultOpen | boolean | false | Initial open state. |
| onOpenChange | (open) => void | — | Fired when the open state changes. |
isOpen
boolean
default: —
Whether the palette is shown.
onClose
() => void
default: —
Fired on Escape, outside click, and after a selection.
onSelect
(item) => void
default: —
Fired on activation, after the item's own onSelect.
filter
(items, query) => items
default: built-in fuzzy
Replace the matcher; return the items to show, already ordered.
isLoading
boolean
default: false
Spinner in the input; suppresses the empty message.
onQueryChange
(query) => void
default: —
Fired as the query changes.
closeOnEscape / closeOnOutsideClick / portal / container / zIndex / blur
—
default: —
Passed through to Backdrop.
hotkey
"mod+k" | string | false
default: "mod+k"
Global open/toggle shortcut. mod = ⌘ on Apple platforms, Ctrl elsewhere. false binds nothing.
defaultOpen
boolean
default: false
Initial open state.
onOpenChange
(open) => void
default: —
Fired when the open state changes.
Data
| Prop | Type | Default | Description |
|---|---|---|---|
| items | CommandPaletteItem[] | — | The commands and destinations. |
| query / defaultQuery | string | "" | Controlled / initial query. |
| emptyQueryItems | CommandPaletteItem[] | all items | List shown while the query is empty (recent / suggested). |
items
CommandPaletteItem[]
default: —
The commands and destinations.
query / defaultQuery
string
default: ""
Controlled / initial query.
emptyQueryItems
CommandPaletteItem[]
default: all items
List shown while the query is empty (recent / suggested).
Appearance
| Prop | Type | Default | Description |
|---|---|---|---|
| placeholder | string | "Type a command or search…" | Input placeholder. |
| emptyMessage | ReactNode | "No results" | Shown when nothing matches. |
| footer | ReactNode | — | Content below the list. |
placeholder
string
default: "Type a command or search…"
Input placeholder.
emptyMessage
ReactNode
default: "No results"
Shown when nothing matches.
footer
ReactNode
default: —
Content below the list.
Layout & positioning
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "sm" | "md" | "lg" | md | Palette width (480 / 600 / 720). |
size
"sm" | "md" | "lg"
default: md
Palette width (480 / 600 / 720).
Accessibility
| Prop | Type | Default | Description |
|---|---|---|---|
| ariaLabel | string | "Command palette" | Accessible name for the dialog and listbox. |
ariaLabel
string
default: "Command palette"
Accessible name for the dialog and listbox.
Styling
| Prop | Type | Default | Description |
|---|---|---|---|
| classNames | { base?, header?, input?, list?, group?, item?, … } | — | Slot classes. |
classNames
{ base?, header?, input?, list?, group?, item?, … }
default: —
Slot classes.
Accessibility
- The dialog traps focus, restores it to the trigger on close, and closes on Escape.
- The input owns a `role="listbox"` of results via `aria-controls`/`aria-activedescendant`; Up/Down move the active option, Enter runs it.
- Result count changes are announced through a live region.