CommandPalette
Usage
Control visibility with open / onOpenChange, or use defaultOpen. Search matches
labels and groups. Running a command closes the palette. Closing returns focus to the control
that opened it. Safari does not focus a button when it is clicked, so there the palette has to see
that click: keep CommandPalette mounted and control open, rather than mounting it only while
it is open.
Long lists
The list shows up to ten rows, counting group labels, and scrolls past that. The active command stays in view as it moves. A group's first command brings the group label with it. A long label wraps and its row grows.
The palette fits the visible screen less a margin. On a short or landscape screen its top offset gives way first, then the list shrinks and scrolls, so the search field and every command stay reachable.
Empty state
When nothing matches, the list shows emptyMessage and a status message announces it once
typing pauses.
Props
| PROP | TYPE | DEFAULT | REQUIRED |
|---|---|---|---|
commands | array | — | yes |
placeholder | string | "Type a command…" | no |
emptyMessage | string | "No results" | no |
open | boolean | — | no |
defaultOpenInitial open state when the palette manages its own state. | boolean | false | no |
onOpenChange | function | — | no |
Accessibility
- Focus stays inside the named dialog. Escape or the overlay dismisses it.
- Up/Down wraps between enabled commands; Home/End moves to first/last; Enter runs the active command.
- The active command scrolls into view the moment it changes, by key or by typing, so its focus indicator is never out of sight. A group's first command brings its group label with it.
- The combobox controls its listbox and points at the active command with
aria-activedescendant; disabled commands exposearia-disabled. - A query that matches nothing is announced through a status message.
- The forwarded ref receives the dialog's
<section>, typedHTMLElement. - Disabled commands cannot activate by keyboard or pointer.
Manifest entry
<CommandPalette
open={open}
onOpenChange={setOpen}
commands={[
{ id: "new", label: "New File", shortcut: "⌘N", onSelect: () => {} },
{ id: "open", label: "Open…", shortcut: "⌘O", onSelect: () => {} },
]}
/>View agent manifest
{
"description": "Modal command launcher: search field over a filtered, keyboard-navigable action list. Command and group labels display uppercase; search input, empty messages, and keyboard shortcuts retain their casing.",
"props": {
"commands": {
"type": "array",
"required": true
},
"placeholder": {
"type": "string",
"default": "Type a command…"
},
"emptyMessage": {
"type": "string",
"default": "No results"
},
"open": {
"type": "boolean"
},
"defaultOpen": {
"type": "boolean",
"default": false,
"description": "Initial open state when the palette manages its own state."
},
"onOpenChange": {
"type": "function"
}
},
"composable_with": [],
"never_inside": [
"CommandPalette"
],
"example": "<CommandPalette\n open={open}\n onOpenChange={setOpen}\n commands={[\n { id: \"new\", label: \"New File\", shortcut: \"⌘N\", onSelect: () => {} },\n { id: \"open\", label: \"Open…\", shortcut: \"⌘O\", onSelect: () => {} },\n ]}\n/>"
}