ComponentsOverlays

Command

A search field over a list of actions or choices. Type to filter, move with the arrow keys, and press Enter to choose. Put it inline, inside a popover picker, or in a command palette dialog.

Command playground

Filter and select commands inline. Type to filter; arrow keys, Home, End, and Enter work from the search field.

Chosen: Nothing selected

Usage

Command usageTSX
import {
  Command,
  CommandEmpty,
  CommandGroup,
  CommandInput,
  CommandItem,
  CommandList,
  CommandSeparator,
  CommandShortcut,
} from "@tulipfarm/sprout/command";

<Command>
  <CommandInput aria-label="Search sample commands" placeholder="Search sample commands…" />
  <CommandList>
    <CommandEmpty>No matching commands.</CommandEmpty>
    <CommandGroup heading="Suggestions">
      <CommandItem onSelect={newDraft}>
        <Plus size={16} aria-hidden="true" />
        New draft
        <CommandShortcut>⌘ N</CommandShortcut>
      </CommandItem>
      <CommandItem onSelect={openFolder}>
        <Folder size={16} aria-hidden="true" />
        Open folder
      </CommandItem>
    </CommandGroup>
    <CommandSeparator />
    <CommandGroup heading="Settings">
      <CommandItem disabled>Unavailable action</CommandItem>
    </CommandGroup>
  </CommandList>
</Command>

Give the input an aria-label or pass label to Command. Each item matches on its text unless you pass a value, and onSelect receives that value. Groups and separators hide while nothing in them matches.

Command palette

CommandDialog pins a Command near the top of the screen in a 24rem dialog. Its title and description are visually hidden but announced. Escape closes it; add showCloseButton for a corner close button. Wire your own shortcut such as ⌘K to open it.

Command palette

CommandDialog pins a Command near the top of the screen. Its title and description are visually hidden; Escape closes it.

Defaultno close button · ⌘K or Ctrl+K toggles it
With close buttonshowCloseButton · custom title and description

Last command: Nothing run yet

Pickers in a popover

Put a Command in PopoverContent size="menu" or size="picker"; both have no padding, so the search and list run edge to edge. Set data-checked on the current item to show a trailing check. Use a long value such as label plus description so both are searchable. Content after Command, such as an effort setting, stays outside the list.

Composer pickers

A Command inside a menu-size (24rem) and a picker-size (18rem) popover above the chat composer. The trailing check marks the current choice.

Mode or agentmenu · two headed groups and a separator · label with a truncated description
Pick the same one again to clear it.
Modelpicker · brand logos · disabled with a reason · effort footer below the list
Models with effort levels keep the picker open.

Ask about your workspace…

Controlled search and list states

Pass value and onValueChange to CommandInput to clear the search when the popover closes or from a button in CommandEmpty. When an item's value is an id, pass its name in keywords so it still matches. Show loading, error with retry, and empty-workspace notes as siblings after CommandList.

Project scope

A picker-size Command with a controlled search, an unlabeled first group, ids as values with names as keywords, and a recovery action when nothing matches.

Chat projectoutline field opens below · scope and ghost badges open above
Disabledwhile a reply is streaming
Project list stateready · loading · failed · refresh failed with last loaded projects · no projects

No action yet

API

Command is a div that owns the search and the active item. It takes label, loop (wrap at the ends), shouldFilter (set false to filter items yourself), and filter(value, search, keywords), which returns a score where 0 hides the item. Matches are ranked: prefix, then word start, then substring, then letters in order. The default is exported as defaultCommandFilter.

CommandInput takes input props plus controlled value and onValueChange, and forwards ref. CommandList scrolls at 18rem. CommandEmpty renders only when nothing matches.CommandGroup takes an optional heading and forceMount. CommandSeparator hides while searching unless alwaysRender.

CommandItem takes value, keywords, disabled, onSelect, forceMount, and data-checked. CommandShortcut is a trailing hint and replaces the check. CommandDialog takes the Dialog root props plus title, description, showCloseButton, closeLabel, container, and className. Every part sets a data-slot.

Accessibility

The input is a combobox that controls the listbox. Focus stays in the input and the active option is announced through aria-activedescendant. Arrow keys move, Home and End jump to the ends, ⌘ or Ctrl with arrows jumps to the first or last item, Alt with arrows jumps between groups, Ctrl+N and Ctrl+P also move, and Enter chooses. Disabled items are skipped. Buttons inside the Command, such as Clear search, keep their own keys.

When nothing matches, the list drops its listbox role, the input reports aria-expanded="false", and the empty message and its actions read as ordinary content. Separators are decorative and hidden from assistive technology.

Highlight and check changes fade over 120ms and stop when reduced motion is requested. In forced-colors mode the active item gets an outline.

Theme tokens

Command uses --sprout-surface, --sprout-text, --sprout-muted, --sprout-line, --sprout-input, --sprout-hover, --sprout-focus, and the control and panel radii. It needs no brand color, so it looks the same with the neutral and TulipFarm themes in light and dark mode.