Command
A command palette component for quick actions, search, and keyboard navigation
Installation
Terminal
Import
Component.tsx
Basic
**Basic Command Menu**
A simple command menu with search functionality and basic items.
Demonstrates the core structure with input, list, and items.
```tsx
<Command>
<Command.Input placeholder="Type a command..." />
<Command.List>
<Command.Item>Action 1</Command.Item>
<Command.Item>Action 2</Command.Item>
</Command.List>
</Command>
```
With Prefix And Suffix
**With Prefix and Suffix**
Shows how to use prefix and suffix elements in a command item.
With Shortcut
**With Shortcut**
Shows how to use a shortcut in a command item.
```tsx
<Command.Item shortcut={{ keys: "F", modifier: "command" }}>
<Command.Value>Photoshop</Command.Value>
</Command.Item>
```
With Groups
**Grouped Commands**
Organizes commands into logical groups with headings and separators.
Perfect for categorizing different types of actions or content.
Large
With Empty State
**With Empty State**
Shows an empty state when no results match the search query.
Essential for providing user feedback during search operations.
```tsx
<Command>
<Command.Input />
<Command.List>
<Command.Empty>No results found.</Command.Empty>
<Command.Item>...</Command.Item>
</Command.List>
</Command>
```
Dialog Mode
Dark Mode
Disabled Command
**Disabled Command**
Shows a disabled command with a disabled item.
Useful for providing user feedback during search operations.
```tsx
<Command>
<Command.Input />
<Command.List>
<Command.Item disabled>...</Command.Item>
</Command.List>
</Command>
```
Controlled State
**Controlled State**
Demonstrates controlled command state with external value management.
Useful for programmatic control and integration with other components.
```tsx
const [value, setValue] = useState("")
<Command value={value} onChange={setValue}>
<Command.Input />
<Command.List>
<Command.Item value="item1">Item 1</Command.Item>
</Command.List>
</Command>
```
Selected: profile
Search: None
With Custom Filtering
**With Custom Filtering**
Shows custom filtering logic and disabled filtering for manual control.
Useful when you need to implement custom search algorithms or server-side filtering.
```tsx
const customFilter = (value, search) => {
return search.length > 0 ? value.toLowerCase().includes(search.toLowerCase()) ? 1 : 0 : 1
}
<Command filter={customFilter}>
<Command.Input />
<Command.List>...</Command.List>
</Command>
```
Custom Filter: Prioritizes exact matches, then prefix matches
Current Search: ""
Large Dataset
**Large Dataset**
Performance test with a large number of items to demonstrate
efficient rendering and search capabilities.
```tsx
<Command>
<Command.Input />
<Command.List>
{largeItemList.map(item => (
<Command.Item key={item.id} value={item.name}>
{item.name}
</Command.Item>
))}
</Command.List>
</Command>
```
Dataset Size: 100 items across 3 categories
Performance: Try searching to see fast filtering in action
Complex Items
**Complex Items**
Demonstrates rich item content with metadata, badges, and custom layouts.
Perfect for file browsers, user selectors, or detailed action lists.
```tsx
<Command.Item value="complex-item">
<div className="flex items-center justify-between w-full">
<div className="flex items-center">
<Icon />
<div>
<div>Title</div>
<div className=" text-secondary-foreground">Subtitle</div>
</div>
</div>
<Badge>New</Badge>
</div>
</Command.Item>
```
Core Mechanism Store
**Core Mechanism: Store & State Management**
Demonstrates the centralized state management system that powers cmdk.
Shows how search, selection, and filtering states are managed centrally.
**Key Features:**
- Centralized state store with subscribe/emit pattern
- Real-time state synchronization across components
- Optimized updates with value comparison guards
- Async scheduling to prevent infinite loops
**How it works:**
The store uses a centralized state with subscribe/emit pattern. Each component subscribes to state changes and re-renders only when necessary.
**Try it:**
- Type in the input to see search query and filtered count change
- Use arrow keys to navigate - watch selectedItemId update
- Press Enter to select - watch value update
- Filter items - watch visible groups change
```tsx
// Access specific state values using selectors
const search = useCommandState((state) => state.search)
const value = useCommandState((state) => state.value)
const filteredCount = useCommandState((state) => state.filtered.count)
const filteredGroups = useCommandState((state) => state.filtered.groups)
// State structure:
// { search, value, selectedItemId, filtered: { count, items, groups } }
```
Internal State Monitor
Search Query: ""
Selected Value: "(none)"
Selected Item ID: (none)
Filtered Count: 0
Update Count: 0
Visible Groups: [none]
Core Mechanism Value Registration
**Core Mechanism: Value Registration System**
Demonstrates how Command.Item and Command.Group automatically extract and register values
using the useValue hook internally. Shows value extraction from props, children, and DOM content.
**Key Features:**
- Automatic value extraction from content or props
- Real-time registration without dependency arrays
- Keyword aliases for enhanced search matching
- DOM attribute synchronization (data-value) for CSS selectors
**How it works:**
- Command.Item and Command.Group internally call useValue() hook
- useValue() runs on every render (no deps array) to keep values synchronized
- It extracts value from: 1) value prop, 2) children text content, 3) DOM textContent
- Values are registered with the global store for search and filtering
- DOM elements get a data-value attribute for CSS selector targeting
**Internal implementation:**
```tsx
// Inside Command.Item component:
const valueDeps = useMemo(() => [value, children, ref], [value, children])
const valueRef = useValue(id, ref, valueDeps, keywords)
```
**Usage:**
```tsx
// You don't need to call useValue directly - it's used internally:
<Command.Item value="explicit-value">Content</Command.Item>
<Command.Item>Content from children</Command.Item>
<Command.Item value="file" keywords={["doc", "document"]}>File</Command.Item>
```
Items: 3
Core Mechanism Async Scheduling
**Core Mechanism: Async Scheduling System**
Demonstrates the scheduling system that prevents infinite loops and optimizes updates.
Command uses `useScheduleLayoutEffect` to batch operations and execute them in the next layout effect cycle.
**Why scheduling is needed:**
- Prevents infinite loops: When operations trigger state changes that trigger more operations
- Batches updates: Multiple operations scheduled with the same ID are deduplicated
- Optimizes DOM updates: All operations execute together in one layout effect cycle
- Breaks recursive cycles: Defers execution to avoid synchronous recursion
**How it works:**
- `schedule(id, callback)` stores callbacks in a Map keyed by ID
- Operations with the same ID replace previous ones (deduplication)
- All scheduled callbacks execute together in the next `useIsomorphicLayoutEffect`
- After execution, the Map is cleared
**Common scheduling priorities:**
- Priority 1: `selectFirstItem()` - High priority, runs first
- Priority 2: `sort()` + `store.emit()` - Value registration
- Priority 3: `filterItems()` + `sort()` - Item mount/unmount
- Priority 4: `filterItems()` - Item removal
- Priority 5: `scrollIntoView()` - Scroll operations
- Priority 7: `updateSelection()` - Selection updates
**What happens when you type:**
1. Search state updates synchronously
2. `schedule(1, selectFirstItem)` - Queued
3. `filterItems()` - Runs immediately
4. `sort()` - Runs immediately
5. All scheduled operations execute in next layout effect
**What happens when item mounts:**
1. Item registers with store
2. `schedule(3, filterItems + sort)` - Queued
3. If no value selected, `selectFirstItem()` runs
4. All operations batch together in layout effect
**Benefits:**
- Prevents infinite loops from recursive updates
- Batches multiple operations into one DOM update cycle
- Deduplicates operations with same priority ID
- Optimizes performance by reducing layout thrashing
```tsx
// Operations are scheduled and batched:
schedule(1, selectFirstItem) // High priority
schedule(5, scrollIntoView) // Medium priority
schedule(7, updateSelection) // Low priority
// All execute together in next layout effect
```
Core Mechanism Fuzzy Search
**Core Mechanism: Fuzzy Search Algorithm**
Shows the sophisticated scoring algorithm that powers cmdk's search functionality.
Demonstrates how different match types get different scores and priorities.
**Key Features:**
- Fuzzy matching with smart scoring
- Prefix matches score higher than substring matches
- Case-sensitive bonus scoring
- Keyword alias support
- Real-time score visualization
```tsx
const score = commandScore(value, search, keywords)
// Returns 0-1 score based on match quality
```
Search Score Visualization
Search Query:
(empty)🎯 Score Legend
1.0 - Exact match
0.9 - Prefix match
0.8 - Word boundary
0.7 - Keyword match
0.6 - Substring match
0.5 - Fuzzy match
0.0 - No match
💡 Try These Searches
file
js
user
set
css
new
search
💡 How it works: The scoring algorithm evaluates match quality using multiple criteria and assigns higher scores to better matches, enabling intelligent ranking.
Nested Items
**Example: Nested Items / Pages**
Demonstrates navigation between different "pages" of items using state management.
Shows how to implement drill-down navigation where selecting one item shows a deeper set of items.
**Key Features:**
- Page stack management with state
- Escape/Backspace to go back to previous page
- Conditional rendering based on current page
- Dynamic page navigation
```tsx
const [pages, setPages] = useState([])
const page = pages[pages.length - 1]
// Navigate deeper
<Command.Item onSelect={() => setPages([...pages, 'projects'])}>
Search projects…
</Command.Item>
```
Navigation Guide:
- • Select items to navigate deeper into subcategories
- • ⎋ or ⌫ (when search is empty) to go back
- • Current path: Home
Conditional Sub Items
**Example: Conditional Sub-Items**
Shows how to conditionally render sub-items that only appear when searching.
Useful for revealing detailed actions only when the user is actively searching.
**Key Features:**
- Sub-items only visible during search
- Custom SubItem component using useCommandState
- Progressive disclosure pattern
- Search-driven UI expansion
```tsx
const SubItem = (props) => {
const search = useCommandState((state) => state.search)
if (!search) return null
return <Command.Item {...props} />
}
```
Search Behavior:
- • Normal view: Shows only main items
- • When searching: Sub-items become visible
- • Try searching for "theme", "dark", or "notification" to see sub-items appear
Async Results
**Example: Asynchronous Results**
Demonstrates loading data asynchronously and displaying results as they become available.
Shows proper loading states and handles dynamic content updates.
**Key Features:**
- Async data fetching simulation
- Loading states with Command.Loading
- Dynamic item rendering
- Automatic filtering and sorting
```tsx
const [loading, setLoading] = useState(false)
const [items, setItems] = useState([])
useEffect(() => {
async function fetchData() {
setLoading(true)
const data = await api.get('/items')
setItems(data)
setLoading(false)
}
fetchData()
}, [])
```
Async Data Loading
Status: 0 items loaded
With Tabs
**Example: Command with Tabs Filter**
Demonstrates how to use Command.Tabs for quick filtering of items by category.
The first tab is always "All" to show all items, followed by category-specific filters.
**Key Features:**
- Tab-based filtering system
- "All" tab shows all items
- Category-specific filtering
- Preserves search functionality within filters
- Integrated with Command's existing filtering system
```tsx
<Command.Tabs value={activeTab} onChange={setActiveTab}>
<Tabs.Item value="all">All</Tabs.Item>
<Tabs.Item value="files">Files</Tabs.Item>
<Tabs.Item value="actions">Actions</Tabs.Item>
</Command.Tabs>
```
Tabbed Filtering:
- • Use tabs to quickly filter items by category
- • "All" tab shows all items across categories
- • Search works within the selected tab filter
- • Use left and right arrow keys to cycle through tabs
- • Currently showing: All Items
- • Items visible: 9
Showing all categories
9 items
API reference
| CommandProps | Type | Default |
|---|---|---|
defaultValue | string |undefined | - |
disablePointerSelection | boolean |undefined | - |
filter | CommandFilter |undefined | - |
label | string |undefined | - |
loop | boolean |undefined | - |
onChange | ((value: string) => void) |undefined | - |
shouldFilter | boolean |undefined | - |
size | undefined |"default" |"large" | "default" |
value | string |undefined | - |
variant | undefined |"default" |"dark" | "default" |
vimBindings | boolean |undefined | - |
| CommandGroupProps | Type | Default |
forceMount | boolean |undefined | false |
heading | ReactNode | - |
value | string |undefined | - |
hidden | boolean |undefined | false |
ref | ((instance: HTMLDivElement |null) => void) |RefObject<HTMLDivElement> |null |undefined | - |
| CommandItemProps | Type | Default |
onSelect | ((value: string) => void) |undefined | - |
disabled | boolean |undefined | - |
value | string |undefined | - |
forceMount | boolean |undefined | - |
keywords | string[] |undefined | - |
prefixElement | ReactNode | - |
shortcut | { keys?: ReactNode; modifier?: KbdKey |KbdKey[] |undefined; } |undefined | - |
suffixElement | ReactNode | - |
ref | ((instance: HTMLDivElement |null) => void) |RefObject<HTMLDivElement> |null |undefined | - |
| CommandListProps | Type | Default |
children | ReactNode | - |
className | string |undefined | - |
label | string |undefined | - |
aria-label | string |undefined | - |
aria-labelledby | string |undefined | - |
hoverBoundary | undefined |"none" |"hover" | - |
orientation | undefined |"vertical" |"horizontal" |"both" | - |
scrollbarMode | undefined |"default" |"padding-y" |"padding-x" |"padding-b" |"padding-t" |"padding-l" |"padding-r" | - |
type | undefined |"hover" |"auto" |"always" |"scroll" | - |
variant | undefined |"default" |"light" |"dark" | - |
| CommandLoadingProps | Type | Default |
label | string |undefined | "Loading..." |
progress | number |undefined | undefined |
| CommandDividerProps | Type | Default |
alwaysRender | boolean |undefined | false |
| CommandInputProps | Type | Default |
value | string |undefined | - |
onChange | ((search: string) => void) |undefined | - |
size | undefined |"default" |"large" | - |
selected | boolean |undefined | - |
className | string |undefined | - |
focusSelection | undefined |"none" |"all" |"end" | - |
onIsEditingChange | ((isEditing: boolean) => void) |undefined | - |
variant | undefined |"default" |"light" |"dark" |"reset" | - |
prefixElement | ReactNode | - |
suffixElement | ReactNode | - |