Command

Finds and runs a command by typing.

Placement

  • inline

  • dialogdefault

States

  • rest

  • searching

  • empty

  • loading

Usage

When to use it
Use
The palette: every action and place in the tool, found by typing, opened with mod+k.
Use
A long list of actions on one page, filtered as the person types.
Not for
A few actions on one thing. Use Dropdown menu.
Not for
The person picks a value for a field. Use Combobox.

Rules

7 rules
Must
Give Command a label that says what it searches. Because it names the search field and the list for a screen reader, which sees neither the placeholder nor the headings while typing.
Must
Write each item as a verb and its object in sentence case; the row sets the capitals. Because an item is an action, and the matched letters are drawn from the words as written.
Should
Add keywords for the other words people use: "rerun" and "retry" for Replay. Because a keyword match ranks last but still finds the item.
Must
Set shouldFilter={false} and mount CommandLoading while results come from a server. Because the list would filter the server's answer a second time, and the pending mark says the search is still going.
Must
Keep CommandDialog's hidden title, or pass your own DialogTitle. Because the dialog is named by its title, and without one a screen reader announces only "dialog".
Never
Box CommandInput in a field or put a frame around a group. Because the search is the list's first ruled row, and a box inside the box is a second edge.
Never
Pad a CommandItem, a group heading or a shortcut in className. Because every row, the search, the headings, the items and their key caps, starts and ends on the 12px --inset, and 40px rows put each 16px icon 12px from its top and from the side, right under the search glyph.

State order

4 states, highest first
1
loading
2
empty
3
searching
4
rest

Accessibility

4 checks
The input is a combobox pointing at the active option with aria-activedescendant; focus never leaves it.
A polite status says how many results there are, and which are unavailable.
The active row lifts to white off the panel between two --line hairlines, text-1 on it 18.3:1 and 13:1; that lift is the focus indicator, and forced colors draw a 2px outline.
Each option carries its place in the ranked order (aria-posinset).

Keyboard

4 keys
Up, Down
Moves the active item; Ctrl+P and Ctrl+N too.
Home, End
First and last item, when the field is empty or with Ctrl.
Enter
Runs the active item.
Escape
Closes the palette and returns focus to what opened it.

Edge cases

5 edge cases
Nothing matches
A sentence and the query take the list's place.
Whitespace typed
No search: every group shows as written.
Slow results
The pending mark takes the search icon's place, so the text never moves.
Touch
The key hints hide; a tap runs an item.
Phone, 390 wide
The palette leaves 16px of page each side.

API

8 props
Command label
string default 'Commands'
Command shouldFilter
boolean default true
Command filter
(value, search, keywords) => number default rank by match
Command loop
boolean default false
CommandDialog title, description
ReactNode | null default hidden
CommandItem value, keywords
string, string[] default its text
CommandItem onSelect
(value) => void
CommandShortcut, CommandHint keys
string

Tokens

18 tokens
--panel
#fafaf7
--page
#ffffff
--line
#e2dfd5
--row-highlight
#ffffff
--row-highlight-edge
var(--line)
--inset
12px
--row
40px
--row-sm
32px
--popup-max
320px
--type-body-sm
400 14px/20px var(--font-sans)
--type-label
400 13px/16px var(--font-mono)
--type-micro
400 11px/14px var(--font-mono)
--text-1
#161512
--text-2
#55524a
--text-3
#6b675e
--pending-cell
3px
--overlay-lg
640px
--z-overlay
50

Install

For your coding agent

GitHub

Please star me pookie

198

A new design system every week

Leave your email before you copy the prompt.