-
Notifications
You must be signed in to change notification settings - Fork 0
React API
Complete API for modern-cmdk/react — the React 19 compound component adapter.
pnpm add modern-cmdk/react
Peer dependencies: react@^19.3.0, @radix-ui/react-dialog@^1.4.4
All components use the "use client" directive and support ref as a prop (React 19 native, no forwardRef).
Root component. Creates the state machine and provides context to all children.
<Command label="Command palette" // accessible label (required) filter={(value, search) => 1} // custom filter function (optional) loop={false} // wrap navigation (optional, default: false) onValueChange={(v) => {}} // callback when active item changes (optional) ref={ref} // ref forwarding (optional) > {children} </Command>
Search input with combobox semantics (role="combobox").
<Command.Input placeholder="Search..." // input placeholder value={search} // controlled value (optional) onValueChange={(v) => {}} // search change callback (optional) ref={ref} // ref forwarding (optional) />
Scrollable results container (role="listbox"). Automatically virtualizes when filteredCount > 100.
<Command.List ref={ref} // ref forwarding (optional) > {children} </Command.List>
Shown when no results match the search query (role="status").
<Command.Empty>No results found.</Command.Empty>
Shown during async operations (aria-busy).
<Command.Loading> {progress && <span>{progress}%</span>} </Command.Loading>
Groups items under a heading (role="group" with aria-labelledby).
<Command.Group heading="Settings" // group heading text forceMount={false} // keep mounted when empty (optional) > <Command.Item>...</Command.Item> </Command.Group>
Selectable item (role="option" with aria-selected).
<Command.Item value="settings" // unique value for filtering/matching keywords={['preferences']} // additional search keywords (optional) disabled={false} // disable selection (optional) onSelect={() => {}} // selection callback forceMount={false} // keep mounted when filtered out (optional) ref={ref} // ref forwarding (optional) > Settings </Command.Item>
Visual separator between groups (role="separator").
<Command.Separator alwaysRender={false} />
Renders keyboard shortcut hint inside an item (<kbd> element).
<Command.Item value="save" onSelect={save}> Save <Command.Shortcut>Ctrl+S</Command.Shortcut> </Command.Item>
Renders a status badge inside an item (<span> element).
<Command.Item value="experimental"> New Feature <Command.Badge>Beta</Command.Badge> </Command.Item>
Wraps Command in a Radix UI Dialog with focus trap, portal, and overlay.
<Command.Dialog open={open} onOpenChange={setOpen} label="Command palette" > <Command.Input placeholder="Type a command..." /> <Command.List> <Command.Item value="home" onSelect={() => navigate('/')}> Home </Command.Item> </Command.List> </Command.Dialog>
Features:
-
@starting-styleCSS animations for GPU-composited enter/exit - Focus trap with return-to-trigger on close
- Portal rendering (escapes z-index stacking)
- Overlay with
backdrop-filter: blur() - Escape key to close
- Click outside to close
Subscribes to machine state via useSyncExternalStore. Accepts an optional selector for fine-grained re-renders.
const search = useCommandState((state) => state.search); const count = useCommandState((state) => state.filteredIds.length);
Returns the raw CommandMachine instance from context. Useful for dispatching custom events.
const machine = useCommandMachine(); machine.send({ type: 'PAGE_PUSH', page: 'settings' });
Automatic virtualization activates when filteredCount > 100. Configure via <Command.List>:
<Command.List> {/* Items are automatically virtualized */} {items.map(item => ( <Command.Item key={item.id} value={item.value}> {item.label} </Command.Item> ))} </Command.List>
Manual control:
<Command.List estimateSize={() => 40} // estimated item height in px overscan={5} // items to render outside viewport > {children} </Command.List>
| Feature | Usage |
|---|---|
ref as prop |
All components accept ref directly, no forwardRef
|
useSyncExternalStore |
Tear-free state subscription |
useTransition |
Non-blocking search updates |
useOptimistic |
Instant active item visual feedback |
"use client" directive |
All components are client-only |
Activity API (<Offscreen>) |
Virtualized item pre-rendering |
The React adapter exposes CSS custom properties for theming:
[data-command-root] { --command-accent: oklch(0.7 0.15 250); --command-bg: oklch(0.15 0.01 260); --command-text: oklch(0.95 0.01 260); --command-border: oklch(0.3 0.02 260); --command-radius: 12px; --command-shadow: 0 16px 70px oklch(0 0 0 / 0.5); }
See Theming for full property reference.
| Attribute | Applied to | Description |
|---|---|---|
[data-command-root] |
Command |
Root container |
[data-command-input] |
Command.Input |
Search input |
[data-command-list] |
Command.List |
Results list |
[data-command-item] |
Command.Item |
Each item |
[data-command-group] |
Command.Group |
Each group |
[data-command-separator] |
Command.Separator |
Separator |
[data-command-empty] |
Command.Empty |
Empty state |
[data-command-loading] |
Command.Loading |
Loading state |
[data-command-item-active] |
Command.Item |
Active/highlighted item |
[data-command-item-disabled] |
Command.Item |
Disabled item |