Components
Command
A fast, composable command menu built on cmdk — fuzzy-searchable items, grouping, keyboard shortcuts, and full keyboard navigation out of the box.
Basic usage
Compose Command with an input, list, and one or more groups. Type to filter the items live.
Groups & shortcuts
Organise items with CommandGroup headings, divide sections with CommandSeparator, and trail each item with a right-aligned CommandShortcut.
Row rhythm comes from the item itself — mt-1 first:mt-0, the same formula used by SelectItem, DropdownMenuItem, and the rest of the menu family — so spacing is identical whether an item sits in a group or directly in the list. Vertical padding reads the --menu-item-py density token, so the whole menu tightens under data-density="compact".
Disabled & empty states
Mark an item disabled to skip it during navigation, and provide a CommandEmpty fallback for when no item matches the search.
Command dialog
CommandDialog drops the same menu into a Dialog and sizes the input and rows up for a full-screen overlay. It renders the screen-reader title and description for you, so the dialog is never nameless — but the built-in strings are Vietnamese, so pass title and description in an English app.
Command menu
Search for a command to run
That hidden header sits beside the dialog content rather than inside the portal, so the title and description are in the document whether the dialog is open or not — expect to find the heading in your page outline.
CommandPalette composite
When you want the finished Linear/Raycast-style palette rather than the primitives, reach for the Tier 2 CommandPalette. You hand it data — groups of items with icons, descriptions and shortcut hints — and it supplies the dialog, the recent group, the loading spinner, the footer bar, and the ⌘K binding. Its search is accent-insensitive for Vietnamese: typing tao viec finds Tạo việc mới. Pass onSearchChange to swap the built-in filter for a server query.
It lives at Tier 2 rather than in the shell on purpose: an app that never mounts AppShell — a standalone settings page, an internal tool — still wants a command palette. When it is inside the shell, set registerShortcut={false}: the shell already binds ⌘K, and two listeners toggling one state cancel each other out. Every user-facing string is overridable. The two sr-only dialog strings are the one place the palette differs from CommandDialog: instead of separate title / description props they arrive together in labels, whose Vietnamese defaults are exported as DEFAULT_COMMAND_PALETTE_LABELS.
Props
Command root props (forwarded to cmdk):
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled value of the highlighted item. Pair with onValueChange; omit for uncontrolled behaviour managed by cmdk. |
defaultValue | string | — | Item highlighted on first render when uncontrolled. |
onValueChange | (value: string) => void | — | Fires when the highlighted item changes. |
label | string | — | Accessible name for the listbox, rendered into a visually hidden label. |
filter | (value, search, keywords) => number | command-score | Custom scoring function controlling which items match the current search. Return 0 to hide an item. |
shouldFilter | boolean | true | Whether the list filters automatically. Set false to filter server-side. |
loop | boolean | false | Whether arrow-key navigation wraps from the last item back to the first. |
disablePointerSelection | boolean | false | Stops hovering an item from making it the highlighted one — useful when the list is driven purely by the keyboard. |
className | string | — | Additional Tailwind classes to merge onto the root element. |
CommandItem props:
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | text content | The value used for filtering and matching. Defaults to the item’s text. |
onSelect | (value: string) => void | — | Called when the item is chosen via click or Enter. |
disabled | boolean | false | Removes the item from keyboard navigation and dims it. |
keywords | string[] | — | Extra terms that should match this item during search. |
forceMount | boolean | false | Keeps the item mounted even when it does not match the current search. |
CommandDialog props (everything else is forwarded to Dialog):
| Prop | Type | Default | Description |
|---|---|---|---|
open / onOpenChange | boolean / (open: boolean) => void | — | Dialog open state, forwarded to the underlying Dialog. |
title | string | 'Bảng lệnh' | Screen-reader title rendered into a visually hidden DialogHeader. Pass an English string in an English app. |
description | string | 'Tìm và chạy một lệnh…' | Screen-reader description for the same header. |
showCloseButton | boolean | true | Whether the dialog renders its close button. |
className | string | — | Classes merged onto the DialogContent wrapper. |
CommandPalette props:
| Prop | Type | Default | Description |
|---|---|---|---|
open / onOpenChangerequired | boolean / (open: boolean) => void | — | Controlled open state. The palette closes itself before running an item’s onSelect. |
groupsrequired | CommandPaletteGroup[] | — | Sections of the palette. Each item carries id, label, and onSelect, plus optional description, icon, shortcut, keywords, and disabled. |
recent | CommandPaletteItem[] | [] | Pinned to the top while the search box is empty. |
recentLabel | string | 'Gần đây' | Heading for the recent group — override it in an English app. |
placeholder | string | 'Tìm lệnh, trang, người…' | Search input placeholder, also used as its aria-label. |
emptyText | string | 'Không tìm thấy kết quả.' | Shown when nothing matches and loading is false. |
onSearchChange | (search: string) => void | — | Providing it switches the palette to server-side search: cmdk’s own filtering is turned off. |
loading | boolean | false | Swaps the magnifier for a spinner and suppresses the empty state while a query is in flight. |
footer | ReactNode | — | Content for the bottom bar — keyboard hints, result counts, status. |
registerShortcut | boolean | true | Binds Cmd/Ctrl+K to toggle the palette. Set false inside the Comitor shell, which already owns that shortcut — two listeners toggle the same state twice and it never opens. |
labels | Partial<CommandPaletteLabels> | DEFAULT_COMMAND_PALETTE_LABELS | Overrides the two sr-only dialog strings, title and description. The defaults are Vietnamese ('Bảng lệnh' / 'Gõ để tìm lệnh, trang hoặc người; dùng mũi tên để chọn và Enter để chạy.') — pass English values in an English app. |
className | string | — | Classes merged onto the dialog content. |
Accessibility
- The menu implements the
combobox/listboxARIA pattern — the input owns the list and announces the active option to screen readers. - Full keyboard support: ↑ / ↓ move between items, Enter selects, and typing filters the list.
- Disabled items expose
data-disabledand are skipped by arrow-key navigation, never receiving focus. - Group headings are linked to their options via
aria-labelledby, giving assistive tech the section context. - A dialog needs a name and a description:
CommandDialogandCommandPaletteboth render them into a visually hidden header rather than leaving it to the caller. CommandPalettelabels its own search box with theplaceholderstring, so the input is named even though it has no visible label.