Command
Press ⌘J anywhere on the page.
Installation
npx shadcn@latest add https://neonkit.heyaadi.com/r/command.jsonUsage
import {
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command"
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Search or jump to…" />
<CommandList>
<CommandEmpty>Nothing lit up.</CommandEmpty>
<CommandGroup heading="Navigate">
<CommandItem shortcut="G D" onSelect={goToDashboard}>Go to Dashboard</CommandItem>
</CommandGroup>
</CommandList>
</CommandDialog>Examples
Inline file jumper
Command works without the dialog. Fuzzy matching finds paths from a few letters, like “uicmd”.
In a popover
A searchable picker. Escape closes the popover, and number keys pick a status before you type.
Server results
shouldFilter={false} shows results as given. CommandLoading runs a scan along the caret line.
API reference
Command
The root: ranks items, owns keyboard navigation and renders the panel. Also accepts native div attributes.
| Prop | Type | Default |
|---|---|---|
label | stringAccessible name for the input and the list. | None |
value | stringThe highlighted item's value, when controlled. | None |
onValueChange | (value: string) => voidCalled when the highlight moves, by keyboard, pointer or a new search. | None |
filter | (value, search, keywords) => numberReturn 0 to hide an item; higher scores rank first. The default ranks prefix, word start, acronym, substring, then subsequence. | fuzzy |
shouldFilter | booleanSet false when results arrive pre-filtered, e.g. from a server. | true |
loop | booleanArrow keys wrap from the last item to the first. | true |
color | NeonColorPalette name or hex. Falls back to --neon-accent, then cyan. | inherited |
CommandDialog
Command inside a native modal <dialog>, 15vh from the top and up to 640px wide. Takes every Command prop too.
| Prop | Type | Default |
|---|---|---|
open | booleanControlled open state. | None |
defaultOpen | booleanInitial state when uncontrolled. | false |
onOpenChange | (open: boolean) => voidCalled on Escape, the esc button or a click on the backdrop. | None |
CommandInput
The search field. Also accepts native input attributes.
| Prop | Type | Default |
|---|---|---|
value | stringThe search, when controlled. | None |
onValueChange | (search: string) => voidCalled on every keystroke. | None |
placeholder | stringAlso the input's name when Command has no label. | "Type a command or search…" |
CommandItem
One option. Also accepts native div attributes.
| Prop | Type | Default |
|---|---|---|
value | stringWhat the search matches and onSelect receives. The visible text stays searchable either way. | its text |
keywords | string[]Extra words that should find this item. | None |
onSelect | (value: string) => voidCalled on click or Enter. | None |
disabled | booleanShown dimmed, skipped by the keyboard, can't be selected. | false |
icon | ReactNodeLeading icon. Lights up while the item is highlighted. | None |
shortcut | stringKeycaps on the right: "⌘K", "Ctrl+K", "G D" or ["⌘", "⇧", "P"]. Chords also set aria-keyshortcuts. | None |
CommandList, CommandGroup, CommandEmpty, CommandLoading, CommandSeparator
Structure. Each accepts the native attributes of its div.
| Prop | Type | Default |
|---|---|---|
CommandList | listboxThe scrolling results. Holds groups, items and the states below. | None |
CommandGroup heading | ReactNodeLabels the group. Hidden while none of its items match. | None |
CommandEmpty | divShown when nothing matches. Defaults to “Nothing lit up.” | None |
CommandLoading | divRender while fetching. Hides CommandEmpty and marks the list busy. | None |
CommandSeparator | divA divider, hidden while searching because results re-order. | None |
Accessibility
- Follows the ARIA combobox pattern: focus stays in the input, which points at the highlighted option with aria-activedescendant.
- Arrow keys (or Ctrl+N and Ctrl+P) move, Alt+Arrow jumps between groups, Home and End go to the ends, Enter runs the item.
- Matched characters are lit in the item's text when children is a string. Custom filters still get the default highlighting.
- A polite live region announces the number of results, “No results” and loading.
- CommandDialog uses showModal(), so the page is inert, Escape closes it and focus returns to where it was.
- The component doesn't bind ⌘K for you: add a keydown listener (see the demo) so it doesn't fight other shortcuts on the page.