Command
A searchable command palette: the Cmd-K menu. Arrows move the highlight, Enter runs the active row, and focus never leaves the input. Built on Radix Dialog; filtering and the roving highlight are hand-rolled.
Installation#
Usage#
import {
Command,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
} from "@/components/ui/command"
export function Example() {
return (
<Command label="Quick actions">
<CommandInput placeholder="Search actions…" />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Create">
<CommandItem value="New project" onSelect={() => create()}>
New project
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
)
}Each CommandItem has a required value (its searchable identity) and an optional keywords array for synonyms. A row that doesn't match the query removes itself, so empty groups and the CommandEmpty state collapse on their own.
Inline#
Skip CommandDialog and use Command directly to embed the palette in a page or a Popover. It brings its own surface, so it reads as a finished card on any background. Disabled rows stay visible but drop out of the keyboard order.
Keyboard#
The search field keeps focus while you navigate (the active row is announced through aria-activedescendant): ↑ / ↓ move the highlight (wrapping at the ends), Home / End jump to the first and last rows, Enter runs the active row, and (inside CommandDialog) Esc closes. Wire a global ⌘K / Ctrl+K listener to toggle the dialog.
const [open, setOpen] = useState(false)
useEffect(() => {
function onKeyDown(e: KeyboardEvent) {
if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
e.preventDefault()
setOpen((o) => !o)
}
}
document.addEventListener("keydown", onKeyDown)
return () => document.removeEventListener("keydown", onKeyDown)
}, [])Motion#
The palette is tuned to keep up with the keyboard. One shared highlight glides between rows as you arrow or sweep the pointer (it jumps without easing when typing changes the rows under it), the list eases its height as the query trims or restores results, and CommandDialog opens and closes on the fast duration, growing down from the search field. The dialog is centered on screen as the full-height panel, so the field you type into stays put while results shrink beneath it. Each motion is a CSS transition, so a held arrow key retargets smoothly instead of queueing. Under prefers-reduced-motion the glide, the height ease and the zoom switch off, leaving a plain fade on the dialog.
Density#
Like the rest of Koala, Command honors the cross-cutting density axis (or a DensityProvider): compact tightens the search height and row padding for an information-dense surface, never touching color or radius.
API reference#
Command
The palette root and search/highlight state owner. Forwards every other div prop.
search/defaultSearch/onSearchChange: the query string (controlled or not).filter:(search, value, keywords?) => number; return0to hide a row, any positive number to keep it. Defaults to a case-insensitive substring match.onSelect: fires when any row is chosen (after that row's ownonSelect).label: accessible name for the result list.density:comfortable(default) orcompact.
CommandDialog
Wraps Command in a Radix Dialog. Takes all Command props plus:
open/defaultOpen/onOpenChange: dialog open state.closeOnSelect: close after a row is chosen (defaulttrue).title/description: visually hidden labels for assistive tech.
CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut
CommandInput: the search field (combobox). It leads with the typed text, aligned to the rows below; passiconfor the magnifying glass, or a node for your own glyph. InsideCommandDialogit ends with anEschint that also closes the dialog on click.CommandList: the scrollinglistboxviewport. It also paints the active row's highlight, so rows need to live inside one.CommandEmpty: shown only when no row matches.CommandGroup: a labeled section (heading) that hides when all its rows filter out.CommandItem: a selectable row.value(required),keywords,disabled,onSelect(value).CommandShortcut: trailing key hint; dropKbdchildren inside.