Command
cmdk-style command palette — search-filtered list inside a modal, with global ⌘K shortcut on web.
At a glance
- Compound API:
Command,Command.Trigger,Command.Dialog,Command.Empty,Command.Group,Command.Item,Command.Shortcut. - Web: global
⌘K/Ctrl+Kshortcut opens the palette. Search is a substring match (case-insensitive). Escape closes. - Native: trigger tap opens the modal; no global keyboard shortcut (React Native has no global key listener).
- Reuses the
Dialogprimitive for the modal surface — inherits focus trap, scroll lock, backdrop blur, and Escape-to-close.
Preview
Anatomy
| Subcomponent | Role |
|---|---|
Command | Root — owns open state and the filter query. Registers ⌘K/Ctrl+K on web. |
Command.Trigger | Element that opens the palette when clicked/pressed. |
Command.Dialog | The modal surface — contains the search input and item list. |
Command.Empty | Shown automatically when the current query matches nothing. |
Command.Group | Labelled section of items. Hidden when all its items are filtered out. |
Command.Item | Selectable entry. Filtered by its text content against the current query. |
Command.Shortcut | Keyboard shortcut hint rendered right-aligned inside an Item. |
Full example
Open state
open (controlled) + onOpenChange for parent-driven state; defaultOpen for uncontrolled mode.
Global keyboard shortcut (web only)
The Command root registers a keydown listener for ⌘K (macOS) / Ctrl+K (Windows/Linux) on window. This shortcut toggles the palette open/closed — no extra wiring needed.
On native, there is no global key listener. Use the Command.Trigger to open the palette.
Filtering
Items are filtered by their text content using a case-insensitive substring match. The query is reset when the palette closes so the next open starts fresh.
An empty query shows everything.
Empty state
Command.Empty renders when the query produces zero matching items across all groups. Place it directly inside Command.Dialog — the wrapper handles visibility automatically.
Shortcuts
Command.Shortcut renders right-aligned text inside a Command.Item:
Disabled items
Disabled items still match the filter but do not fire onSelect when clicked.
Props
Command
| Prop | Type | Default | Description |
|---|---|---|---|
defaultOpen | boolean | false | Uncontrolled initial open state. @defaultValue false |
onOpenChange | (open: boolean) => void | — | Fires with the new open state. |
open | boolean | — | Controlled open state. |
Command.Dialog
The modal surface that contains the search input and the item list. Accepts:
children—Command.Empty,Command.Group, andCommand.Itemnodes.placeholder— text shown inside the search<input>. Defaults to"Type a command or search…".className— for custom width / padding overrides.
Command.Item
A single selectable row inside a Command.Group. Accepts:
children— row content. Can include text and aCommand.Shortcut.onSelect— callback fired when the item is clicked or activated via Enter.disabled— renders the item as non-interactive (still shown; filtered matches still apply).
v2 / deferred
- Fuzzy search — v1 uses simple substring matching; fuzzy ranking (like fuse.js or cmdk's built-in) is a v2 follow-up.
- Async / remote items — v1 works with static children only; async loading with a loading state is deferred.
- Customizable shortcut — v1 hardcodes
⌘K/Ctrl+K; ashortcutprop onCommandis planned for v2. - Keyboard navigation — Arrow-Up/Down between items, Enter to select. v1 relies on standard DOM focus management via tab order; explicit arrow-key navigation is a v2 polish item.