Menu
Command
A search field above a filtered list of commands or pages, inline or in a dialog.
Import
import { Command, CommandDialog, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandShortcut, CommandSeparator } from "@booleanpress/ui/command"Also install cmdk: pnpm add cmdk
Usage
Command is cmdk with the package's look. Typing filters the items; the first match is highlighted and Enter runs its onSelect. Name the search field with cmdk's label prop on Command.
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@booleanpress/ui/command"
export function Pages() {
return (
<Command label="Search pages">
<CommandInput placeholder="Search for a page" />
<CommandList>
<CommandEmpty>No results.</CommandEmpty>
<CommandGroup heading="Pages">
<CommandItem onSelect={() => open("/logs")}>Email log</CommandItem>
<CommandItem onSelect={() => open("/mailers")}>Mailers</CommandItem>
</CommandGroup>
</CommandList>
</Command>
)
}CommandDialog puts the same parts in a dialog; control it with open and onOpenChange, and open it from a button and a shortcut of your own. Its hidden title and description are inside the dialog and come from the provider's commandTitle and commandDescription; pass title and description to override them. The dialog's title also names the search field. Give CommandItem a value when its text is not what people should search, keywords for extra search words, and disabled to skip it. CommandShortcut shows a key hint; it does not bind the key. cmdk filters by itself: pass shouldFilter={false} to Command and filter the items yourself for server-side search.
Examples
Basic
An inline list with two groups and shortcut hints.
In a dialog
CommandDialog, opened by the button or by ⌘J / Ctrl+J.
Empty result
CommandEmpty shows when nothing matches the search.
Disabled item
A disabled item is skipped by the arrow keys and cannot be chosen.
Accessibility
- Semantics
- The search field is an
inputwithrole="combobox",aria-expanded,aria-controlsandaria-activedescendant; the list is arole="listbox"named from the provider'ssuggestionsstring, and each item arole="option"witharia-selected. Groups arerole="group"named by their heading. Focus stays in the field while the arrow keys move the highlight. - Labels
- Name an inline command with the
labelprop onCommand; it names the search field.CommandDialognames it with the dialog's title. Translate the list's name, the dialog title and the dialog description in the provider. - Focus
- Focus goes to the search field when a
CommandDialogopens and returns to what opened it on close. Inline, the field is a normal tab stop; the list is never focused. - Known limits
- cmdk also binds Ctrl+N, Ctrl+J (next) and Ctrl+P, Ctrl+K (previous) while the field has focus. Pass
vimBindings={false}toCommandif your shortcuts collide. - While nothing matches, cmdk leaves an empty
listboxwith theCommandEmptymessage beside it; axe reports an empty listbox asaria-required-children. The message is still read as text. - Do not put
CommandSeparatorinside the list: cmdk renders it asrole="separator"in alistbox, which axe reports asaria-required-children. Separate groups by their headings. CommandShortcutis only a hint. Bind the key yourself, and not on a key that cmdk uses.
- cmdk also binds Ctrl+N, Ctrl+J (next) and Ctrl+P, Ctrl+K (previous) while the field has focus. Pass
Keyboard
| Key | Behaviour |
|---|---|
| ↓ | Highlights the next item, wrapping from the last to the first (loop). |
| ↑ | Highlights the previous item. |
| Home | Highlights the first item. |
| End | Highlights the last item. |
| Enter | Runs the highlighted item's onSelect. |
| Escape | In a CommandDialog, closes it and returns focus. |
API
Command
Renders cmdk Command and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
disablePointerSelection | boolean | Optionally set to true to disable selection via pointer events. | |
filter | CommandFilter | Custom filter function for whether each command menu item should matches the given search query.
It should return a number between 0 and 1, with 1 being the best match and 0 being hidden entirely.
By default, uses the command-score library. | |
label | string | Accessible label for this command menu. Not shown visibly. | |
loop | boolean | Optionally set to true to turn on looping around when using the arrow keys. | |
onValueChange | ((value: string) => void) | Event handler called when the selected item of the menu changes. | |
shouldFilter | boolean | Optionally set to false to turn off the automatic filtering and sorting.
If false, you must conditionally render valid items based on the search query yourself. | |
value | string | Optional controlled state of the selected command menu item. | |
vimBindings | boolean | Set to false to disable ctrl+n/j/p/k shortcuts. Defaults to true. |
CommandDialog
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | ||
defaultOpen | boolean | ||
description | string | The hidden dialog description. Defaults to the provider's commandDescription. | |
modal | boolean | ||
onOpenChange | ((open: boolean) => void) | Called with true or false when it opens or closes. | |
open | boolean | Whether it is open. Pair it with onOpenChange. | |
showCloseButton | boolean | true | Render the × button. true by default. |
title | string | The hidden dialog title, which also names the search field. Defaults to the provider's commandTitle. |
CommandInput
Renders cmdk Command.Input and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
onValueChange | ((search: string) => void) | Event handler called when the search value changes. | |
value | string | Optional controlled state for the value of the search input. |
CommandList
Renders cmdk Command.List and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
label | string | Accessible label for this List of suggestions. Not shown visibly. |
CommandEmpty
Renders cmdk Command.Empty and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean |
CommandGroup
Renders cmdk Command.Group and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
forceMount | boolean | Whether this group is forcibly rendered regardless of filtering. | |
heading | ReactNode | Optional heading to render for this group. | |
value | string | If no heading is provided, you must provide a value that is unique for this group. |
CommandItem
Renders cmdk Command.Item and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
disabled | boolean | Whether this item is currently disabled. | |
forceMount | boolean | Whether this item is forcibly rendered regardless of filtering. | |
keywords | string[] | Optional keywords to match against when filtering. | |
onSelect | ((value: string) => void) | Event handler for when this item is selected, either via click or keyboard selection. | |
value | string | A unique value for this item.
If no value is provided, it will be inferred from children or the rendered textContent. If your textContent changes between renders, you must provide a stable, unique value. |
CommandShortcut
Renders a span and passes it every other prop.
CommandSeparator
Renders cmdk Command.Separator and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
alwaysRender | boolean | Whether this separator should always be rendered. Useful if you disable automatic filtering. | |
asChild | boolean |
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="command" (Command), data-slot="command-input-wrapper" (CommandInput), data-slot="command-list" (CommandList), data-slot="command-empty" (CommandEmpty), data-slot="command-group" (CommandGroup), data-slot="command-item" (CommandItem), data-slot="command-shortcut" (CommandShortcut), data-slot="command-separator" (CommandSeparator).
Provider strings: commandTitle, commandDescription, suggestions (BooleanUIProvider's strings).
Theming
The list is a floating surface: --popover and --popover-foreground. The highlighted item uses --accent and --accent-foreground.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--accent | background |
--accent-foreground | text |
--border | background |
--foreground | text |
--muted-foreground | text |
--popover | background |
--popover-foreground | text |