CommandBox
A command palette for quick navigation, search, and actions with keyboard shortcuts and fuzzy search.
Installation
npx vayu-ui init #one time onlynpx vayu-ui add commandboxnpx vayu-ui add -t commandbox #with test case needsUsage
Command Palette
Press Ctrl+Shift+P or click the button
Use arrow keys to navigate, Enter to select, Escape to close
Inline CommandBox
Without overlay backdrop
With Descriptions
Items with additional context
Simple List
Without groups or shortcuts
Loading State
Async command loading
<CommandBox open={open} onOpenChange={setOpen} onSelect={handleSelect}>
<CommandBox.Overlay>
<CommandBox.Input placeholder="Type a command or search..." />
<CommandBox.List>
<CommandBox.Group label="Navigation">
<CommandBox.Item
id="home"
shortcut={['⌘', 'H']}
icon={<Home className="w-4 h-4" />}
>
Go to Home
</CommandBox.Item>
<CommandBox.Item
id="search"
shortcut={['⌘', 'S']}
icon={<Search className="w-4 h-4" />}
>
Search
</CommandBox.Item>
</CommandBox.Group>
<CommandBox.Separator />
<CommandBox.Group label="Actions">
<CommandBox.Item
id="new-file"
shortcut={['⌘', 'N']}
icon={<Plus className="w-4 h-4" />}
>
New File
</CommandBox.Item>
<CommandBox.Item id="settings" icon={<Settings className="w-4 h-4" />}>
Open Settings
</CommandBox.Item>
</CommandBox.Group>
<CommandBox.Empty>No commands found.</CommandBox.Empty>
</CommandBox.List>
</CommandBox.Overlay>
</CommandBox>Anatomy
import { CommandBox } from 'vayu-ui';
<CommandBox open={open} onOpenChange={setOpen}>
<CommandBox.Overlay>
<CommandBox.Input placeholder="Search..." />
<CommandBox.List>
<CommandBox.Group label="Section">
<CommandBox.Item id="item-1" shortcut={['⌘', 'N']} icon={<Icon />}>
Item Label
</CommandBox.Item>
</CommandBox.Group>
<CommandBox.Separator />
<CommandBox.Empty>No results found.</CommandBox.Empty>
</CommandBox.List>
</CommandBox.Overlay>
</CommandBox>;- CommandBox — Root container. Manages open/close state, search filtering, and keyboard navigation.
- CommandBox.Overlay — Portal-based overlay with backdrop. Renders the command box centered on screen.
- CommandBox.Input — Search input with combobox ARIA role. Handles arrow key navigation and Enter selection.
- CommandBox.List — Scrollable listbox container for items and groups.
- CommandBox.Group — Groups items under a sticky label header.
- CommandBox.Item — Individual option with support for icons, descriptions, keyboard shortcuts, and disabled state.
- CommandBox.Separator — Visual divider between groups.
- CommandBox.Empty — No-results message shown when search yields no matches.
Accessibility
- Keyboard Support:
ArrowDown— Move highlight to the next item.ArrowUp— Move highlight to the previous item.Enter— Select the highlighted item and close the palette.Home— Jump highlight to the first item.End— Jump highlight to the last item.Escape— Close the palette.- Modifier shortcuts (e.g.,
⌘+N,Ctrl+K) — Select the matching item directly.
- ARIA Attributes:
- Input has
role="combobox"witharia-expanded,aria-controls, andaria-activedescendant. - List has
role="listbox"linked viaaria-controls. - Each item has
role="option"witharia-selectedandaria-disabled. - Groups use
role="group"witharia-label. - Separator uses
role="separator"witharia-orientation="horizontal". - Empty state uses
role="status"witharia-live="polite". - Backdrop is marked
aria-hidden="true".
- Input has
- Focus Behavior:
- Input auto-focuses when the palette opens.
- Highlighted item scrolls into view automatically.
- Body scroll is locked while the palette is open.
Screen reader behavior
When the command palette opens, the screen reader announces the search input as a combobox. As the user types, filtered results update in the live region. The highlighted item is announced via aria-activedescendant on the input. Each option is announced with its role ("option") and selected state. Group labels are announced when navigating into a new group via aria-label on the group container. The empty state message is announced through the aria-live="polite" region when no results match. When the palette closes, focus returns to the previously focused element.
Component Folder Structure
CommandBox/
├── CommandBox.tsx # Root component with state management and filtering
├── CommandBoxInput.tsx # Search input with combobox ARIA role
├── CommandBoxList.tsx # Scrollable listbox container
├── CommandBoxItem.tsx # Self-registering option with selection states
├── CommandBoxGroup.tsx # Grouped items with sticky label header
├── CommandBoxSeparator.tsx # Visual divider between groups
├── CommandBoxEmpty.tsx # No-results state with aria-live
├── CommandBoxOverlay.tsx # Portal-based overlay with backdrop
├── hooks.ts # Context provider and fuzzy search utility
├── types.ts # TypeScript type definitions
└── index.ts # Re-exports all components and typesProps
CommandBox (Root)
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | false | Initial open state for uncontrolled mode. |
onOpenChange | (open: boolean) => void | — | Callback when open state changes. |
onSelect | (item: CommandBoxItemData) => void | — | Callback when an item is selected. |
filter | (item, search) => number | — | Custom filter scoring function. |
showShortcuts | boolean | true | Show keyboard shortcut badges on items. |
loading | boolean | false | Show loading state. |
children | ReactNode | — | Component children. |
className | string | — | Additional CSS classes. |
CommandBox.Input
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | 'Type a command or search...' | Input placeholder text. |
icon | ReactNode | <Search /> | Custom search icon. |
className | string | — | Additional CSS classes. |
CommandBox.List
| Prop | Type | Default | Description |
|---|---|---|---|
maxHeight | string | '320px' | Maximum height before scrolling. |
className | string | — | Additional CSS classes. |
CommandBox.Item
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Unique identifier. Required. |
disabled | boolean | false | Disable selection. |
shortcut | string[] | — | Keyboard shortcut keys (e.g., ['⌘', 'N']). |
icon | ReactNode | — | Icon displayed before the label. |
description | string | — | Secondary description text. |
title | string | — | Item title (falls back to children if string). |
className | string | — | Additional CSS classes. |
CommandBox.Group
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Group heading label. Required. |
className | string | — | Additional CSS classes. |
CommandBox.Empty
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | 'No results found' | Custom empty state message. |
className | string | — | Additional CSS classes. |
CommandBox.Separator
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
CommandBox.Overlay
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Content to render inside. |
className | string | — | Additional CSS classes. |