Command
A searchable list of actions, on the page or in a dialog.
About
Command is Base UI's Autocomplete rendered inline, not the cmdk package
that shadcn's Command is built on. The list is always open, the input filters
it, and an item runs its onClick when clicked or when Enter is pressed while
it is highlighted. The trade-off is the data shape. Options go through items
and render from a function child, the way a Combobox does.
Installation
Install the following dependencies:
Set up the token layer and the StyleX compiler, if you have not already. See
Installation, and paste states.ts and state-styles.ts
from the same page. states.ts holds the dimmed item style, and an item reads
its highlight and disabled state through state-styles.ts. The list needs interop.css
for its hidden scrollbar and for the icons it does not render.
Add Input, Input Group
and Dialog. The search field is an InputGroup, and
CommandDialog is a Dialog.
Copy and paste the following code into your project.
Update the import paths to match your project setup.
Usage
Items shaped { value, label } filter on label. For any other shape, pass
itemToStringValue to Command.
Composition
CommandEmpty sits before CommandList, not inside it. The list is a
listbox, and a status message is not one of its options.
Groups
Pass groups shaped { value, items } to items. CommandList takes a
function child that receives each group; render a CommandGroup with the
group's items and a function child that receives each item.
Filtering drops a group with no match left, so put the CommandSeparator
before every group but the first rather than between groups.
Basic
Put the Command inside a CommandDialog and control it with open and
onOpenChange. Close it from an item's onClick.
Dialog
Toggle the dialog from a keyboard shortcut. Nothing in the component binds one.
Press ⌘J
Shortcuts
Use CommandShortcut to show a key combination at the trailing edge of an
item. It displays the key only.
Scrollable
The list stops at 18rem and scrolls. The highlighted item scrolls into view.
API reference
Pass render to replace a part's element or compose it with another component.
Every part wraps the Base UI Autocomplete part of the same name and accepts
its props. See the Base UI reference
for the full list. Each styled part also takes xstyle and className.
CommandItem also takes style, which is real inline CSS merged over the style
its Base UI state resolves to.
Command
| Prop | Type | Default |
|---|---|---|
items | readonly Item[] | readonly Group[] | — |
autoHighlight | boolean | "always" | "always" |
keepHighlight | boolean | true |
itemToStringValue | (item: Item) => string | — |
filter | (item, query, toString) => boolean | — |
value | string | — |
onValueChange | (value: string, details) => void | — |
value is the input's text. inline and open are set and cannot be
changed.
CommandDialog
| Prop | Type | Default |
|---|---|---|
open | boolean | — |
onOpenChange | (open: boolean, details) => void | — |
title | string | "Command Palette" |
description | string | "Search for a command to run..." |
showCloseButton | boolean | false |
title and description are read to screen readers and not shown. The popup
sits a third of the way down the viewport and stays put as the list changes
height.
CommandGroup
| Prop | Type | Default |
|---|---|---|
heading | ReactNode | — |
items | readonly Item[] | — |
children | ReactNode | (item: Item, index: number) => ReactNode | — |
CommandItem
| Prop | Type | Default |
|---|---|---|
value | Item | — |
onClick | (event) => void | — |
disabled | boolean | false |
commandStyles
The style maps behind the component. Spread them onto any element.
| Key | What it is |
|---|---|
root | The panel: surface, radius, padding |
list | The scrolling list |
empty | The empty message |
group | A group's padding |
heading | A group heading |
separator | The hairline between groups |
item | An item's row and type |
itemHighlighted | The highlight fill and inset ring |
itemDisabled | The dimmed, inert item |
shortcut | CommandShortcut |
itemDisabled is disabled from states in theme/states.ts, the same dim
every other control uses. root keeps its own fill. The panel is inline, so it
takes no popup ring or shadow.
Data attributes
| Attribute | On | Effect |
|---|---|---|
data-slot="command" | the panel | Targets the panel from a parent |
data-slot="input-group" | the field | The frame CommandInput renders |
data-slot="command-list" | the list | Targets the list from a parent |
data-slot="command-group" | a group | Targets a group from a parent |
data-slot="command-group-heading" | a heading | Targets a heading from a parent |
data-slot="command-item" | an item | Targets items from a parent |
data-highlighted, data-disabled | an item | Base UI writes them |
data-slot="dialog-content" | the dialog | Targets the animated dialog panel |