Command

A searchable command palette: the Cmd-K menu. Arrows move the highlight, Enter runs the active row, and focus never leaves the input. Built on Radix Dialog; filtering and the roving highlight are hand-rolled.

Press ⌘ K or click the button.

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add command

Usage#

usage.tsxTSX
import {  Command,  CommandInput,  CommandList,  CommandEmpty,  CommandGroup,  CommandItem,} from "@/components/ui/command"export function Example() {  return (    <Command label="Quick actions">      <CommandInput placeholder="Search actions…" />      <CommandList>        <CommandEmpty>No results found.</CommandEmpty>        <CommandGroup heading="Create">          <CommandItem value="New project" onSelect={() => create()}>            New project          </CommandItem>        </CommandGroup>      </CommandList>    </Command>  )}

Each CommandItem has a required value (its searchable identity) and an optional keywords array for synonyms. A row that doesn't match the query removes itself, so empty groups and the CommandEmpty state collapse on their own.

Inline#

Skip CommandDialog and use Command directly to embed the palette in a page or a Popover. It brings its own surface, so it reads as a finished card on any background. Disabled rows stay visible but drop out of the keyboard order.

Create
New project
Invite teammate
Navigate
Dashboard
Account
Support (offline)

Highlight with ↑ ↓, run with Enter.

Keyboard#

The search field keeps focus while you navigate (the active row is announced through aria-activedescendant): ↑ / ↓ move the highlight (wrapping at the ends), Home / End jump to the first and last rows, Enter runs the active row, and (inside CommandDialog) Esc closes. Wire a global ⌘K / Ctrl+K listener to toggle the dialog.

shortcut.tsxTSX
const [open, setOpen] = useState(false)useEffect(() => {  function onKeyDown(e: KeyboardEvent) {    if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {      e.preventDefault()      setOpen((o) => !o)    }  }  document.addEventListener("keydown", onKeyDown)  return () => document.removeEventListener("keydown", onKeyDown)}, [])

Motion#

The palette is tuned to keep up with the keyboard. One shared highlight glides between rows as you arrow or sweep the pointer (it jumps without easing when typing changes the rows under it), the list eases its height as the query trims or restores results, and CommandDialog opens and closes on the fast duration, growing down from the search field. The dialog is centered on screen as the full-height panel, so the field you type into stays put while results shrink beneath it. Each motion is a CSS transition, so a held arrow key retargets smoothly instead of queueing. Under prefers-reduced-motion the glide, the height ease and the zoom switch off, leaving a plain fade on the dialog.

Density#

Like the rest of Koala, Command honors the cross-cutting density axis (or a DensityProvider): compact tightens the search height and row padding for an information-dense surface, never touching color or radius.

Appearance
Light
Dark
System
Resources
GitHub repository

API reference#

Command

The palette root and search/highlight state owner. Forwards every other div prop.

  • search / defaultSearch / onSearchChange: the query string (controlled or not).
  • filter: (search, value, keywords?) => number; return 0 to hide a row, any positive number to keep it. Defaults to a case-insensitive substring match.
  • onSelect: fires when any row is chosen (after that row's own onSelect).
  • label: accessible name for the result list.
  • density: comfortable (default) or compact.

CommandDialog

Wraps Command in a Radix Dialog. Takes all Command props plus:

  • open / defaultOpen / onOpenChange: dialog open state.
  • closeOnSelect: close after a row is chosen (default true).
  • title / description: visually hidden labels for assistive tech.

CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator, CommandShortcut

  • CommandInput: the search field (combobox). It leads with the typed text, aligned to the rows below; pass icon for the magnifying glass, or a node for your own glyph. Inside CommandDialog it ends with an Esc hint that also closes the dialog on click.
  • CommandList: the scrolling listbox viewport. It also paints the active row's highlight, so rows need to live inside one.
  • CommandEmpty: shown only when no row matches.
  • CommandGroup: a labeled section (heading) that hides when all its rows filter out.
  • CommandItem: a selectable row. value (required), keywords, disabled, onSelect(value).
  • CommandShortcut: trailing key hint; drop Kbd children inside.

FAQ#

Use Command for an open-ended, searchable list of actions or destinations (the ⌘K pattern), where typing to filter is the primary interaction. DropdownMenu and Select are for short, fixed sets that you pick from without searching.