Overview
Command is a keyboard-first command palette — typically opened with ⌘K — that allows users to search, navigate, and trigger actions without leaving the keyboard. It supports grouped results, icons, and keyboard shortcuts.
Installation
npm install @araf-ds/core
Usage
import {
Command ,
CommandDialog ,
CommandInput ,
CommandList ,
CommandEmpty ,
CommandGroup ,
CommandItem ,
CommandShortcut ,
CommandSeparator ,
} from "@araf-ds/core"
export default function Example () {
const [ open , setOpen ] = useState ( false )
// Open with ⌘K
useEffect (() => {
const down = ( e : KeyboardEvent ) => {
if ( e . key === "k" && ( e . metaKey || e . ctrlKey )) {
e . preventDefault ()
setOpen ( prev => ! prev )
}
}
document . addEventListener ( "keydown" , down )
return () => document . removeEventListener ( "keydown" , down )
}, [])
return (
< CommandDialog open = { open } onOpenChange = { setOpen } >
< CommandInput placeholder = "Type a command or search..." />
< CommandList >
< CommandEmpty > No results found. </ CommandEmpty >
< CommandGroup heading = "Navigation" >
< CommandItem >
< HomeIcon size = { 14 } />
Home
< CommandShortcut > G H </ CommandShortcut >
</ CommandItem >
< CommandItem >
< UserIcon size = { 14 } />
Profile
< CommandShortcut > G P </ CommandShortcut >
</ CommandItem >
</ CommandGroup >
< CommandSeparator />
< CommandGroup heading = "Actions" >
< CommandItem >
< PlusIcon size = { 14 } />
New document
</ CommandItem >
</ CommandGroup >
</ CommandList >
</ CommandDialog >
)
}
Variants
Inline (Embedded in Page)
Use Command directly (without CommandDialog) to embed the palette inline — useful for search inputs, comboboxes, and filter panels.
< Command className = "rounded-lg border shadow-md w-[320px]" >
< CommandInput placeholder = "Search frameworks..." />
< CommandList >
< CommandEmpty > No framework found. </ CommandEmpty >
< CommandGroup >
{ frameworks . map ( fw => (
< CommandItem
key = { fw . value }
value = { fw . value }
onSelect = { setValue }
>
< CheckIcon
className = { cn ( value === fw . value ? "opacity-100" : "opacity-0" ) }
size = { 12 }
/>
{ fw . label }
</ CommandItem >
)) }
</ CommandGroup >
</ CommandList >
</ Command >
Dialog (Global ⌘K Palette)
The most common pattern — full-screen overlay opened with a keyboard shortcut.
// Trigger button shown in the UI
< Button
variant = "outline"
onClick = { () => setOpen ( true ) }
className = "gap-2 text-muted-foreground"
>
< SearchIcon size = { 14 } />
Search...
< kbd className = "ml-auto text-xs border rounded px-1" > ⌘K </ kbd >
</ Button >
< CommandDialog open = { open } onOpenChange = { setOpen } >
< CommandInput placeholder = "Type a command or search..." />
< CommandList >
< CommandEmpty > No results found. </ CommandEmpty >
< CommandGroup heading = "Suggestions" >
< CommandItem onSelect = { () => router . push ( "/dashboard" ) } >
< LayoutDashboardIcon size = { 14 } /> Dashboard
</ CommandItem >
< CommandItem onSelect = { () => router . push ( "/settings" ) } >
< SettingsIcon size = { 14 } /> Settings
< CommandShortcut > ⌘, </ CommandShortcut >
</ CommandItem >
</ CommandGroup >
</ CommandList >
</ CommandDialog >
API Reference
Command
Controlled selected item value.
Callback fired when the selected item changes.
filter
(value: string, search: string) => number
Custom filter function. Return 1 to show, 0 to hide. Default: fuzzy search.
Set to false to disable built-in filtering (handle externally with async search).
CommandDialog
Callback fired when open state changes.
Placeholder text shown when empty.
CommandItem
The value used for filtering and selection.
Callback fired when the item is selected (Enter or click).
CommandGroup
Group label shown above the items.
Accessibility
CommandDialog uses role="dialog" with aria-modal="true"
CommandInput is a search input with role="combobox" and aria-expanded
CommandList has role="listbox"; each CommandItem has role="option"
Keyboard: Arrow Up/Down navigates, Enter selects, Escape closes, typing filters
CommandEmpty is announced by screen readers when no results match
Do’s & Don’ts
Do
Register ⌘K / Ctrl+K globally to open the command palette
Group items with CommandGroup and clear heading labels
Show a visible keyboard shortcut hint in the UI (e.g. a button with ⌘K badge)
Use shouldFilter={false} for server-side or async search
Don't
Don’t put destructive actions in the command palette without confirmation
Don’t list more than 20–30 items without grouping or filtering
Don’t use Command as a regular dropdown — use Select or DropdownMenu
Don’t forget to close the dialog after an action is selected