Keyboard navigation, actions and record search from anywhere. Three layers: list primitives, a top-anchored CommandDialog, and a ready-made CommandPalette wired to a registry that pages, apps and the App shell's nav all contribute to.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { CommandProvider, CommandPalette, useRegisterCommands } from "@vamos-ui/react";
// App shell mounts these for you.
<CommandProvider actions={[{ id: "cms.post.new", title: "New post", shortcut: "mod+shift+n", global: true, perform: newPost }]}>
<App />
<CommandPalette />
</CommandProvider>
// Inside a page: commands that exist only while it is mounted.
useRegisterCommands([{ id: "cms.post.publish", title: "Publish post", group: "This post", perform: publish }]);The kit only binds mod+k (palette) and mod+\ (sidebar rail). It never binds mod+b, mod+i or other editor shortcuts.
With a CommandSource active the palette ranks local commands itself (shouldFilter={false}), so local and remote results never fight over order.
Examples
Command dialog
CommandDialog is anchored near the top and fills the screen on phones. Focus starts in the input; Esc closes and returns focus.
Page commands
useRegisterCommands adds commands while the page is mounted and always calls the latest closure. A perform that returns a promise keeps the palette open with a spinner on the item.
“Local SEO checklist for 2026” · Draft
Record search
A CommandSource is debounced, aborted on every keystroke and shown in its own group with a thin progress bar while it loads. A failing source shows one line while other groups keep working.
Sub-pages
An action with children opens a sub-page (a chip in the input); Backspace on an empty input goes back. Children can load lazily. open("id") jumps straight to a sub-page.
Locale-aware matching
Matching folds text for the current locale: in Turkish “istanbul” finds “İstanbul”, “isik” finds “Işık”. Strings come from the dictionary.
API
Command
| Prop | Type | Default |
|---|---|---|
filterScore 0–1. The default folds text for the locale: exact > prefix > word start > contains > keyword. | (value, search, keywords) => number | cmdkFilter(locale) |
shouldFilterfalse: render only the items you want (async results). | boolean | true |
loopArrow keys wrap around. | boolean | true |
labelAccessible name of the listbox (command.label). | string | "Command palette" |
value / onValueChangeControlled highlighted item. | string | — |
CommandInput
| Prop | Type | Default |
|---|---|---|
placeholderFrom the dictionary (command.placeholder). | string | "Type a command or search…" |
chipBreadcrumb chip before the input (current sub-page). | ReactNode | — |
endTrailing slot (spinner, filter). | ReactNode | — |
value / onValueChangeControlled query. | string | — |
CommandItem
| Prop | Type | Default |
|---|---|---|
valueStable unique value; inferred from text when omitted. | string | — |
keywordsSynonyms used for matching. | string[] | — |
onSelectClick or Enter. | (value: string) => void | — |
iconLeading icon. | ReactNode | — |
descriptionSecond line. | ReactNode | — |
shortcutDisplay only: "mod+shift+n". | string | string[] | — |
badgeTrailing meta, e.g. an app badge. | ReactNode | — |
chevronTrailing chevron (opens a sub-page). | boolean | — |
loadingSpinner in place of the icon, aria-busy. | boolean | — |
disabledSkipped by the keyboard. | boolean | — |
CommandGroup · CommandEmpty · CommandLoading · CommandSeparator · CommandShortcut
| Prop | Type | Default |
|---|---|---|
headingCommandGroup title (also its accessible name). | ReactNode | — |
childrenCommandEmpty / CommandLoading content; defaults from the dictionary. | ReactNode | "No results found." |
keysCommandShortcut keys, platform-aware (⌘ / Ctrl). | string | string[] | — |
CommandDialog
| Prop | Type | Default |
|---|---|---|
open / defaultOpen / onOpenChangeDialog state. | boolean | — |
size560 / 680 px. Fullscreen below 640px. | "md" | "lg" | "lg" |
titleHidden dialog title. | string | "Command palette" |
commandPropsProps for the inner Command (filter, shouldFilter…). | CommandProps | — |
CommandProvider
| Prop | Type | Default |
|---|---|---|
actionsStatic commands for the provider's lifetime. | CommandAction[] | — |
sourcesAsync record search. | CommandSource[] | — |
registryUse an existing registry (createCommandRegistry). | CommandRegistry | — |
shortcutToggle shortcut. Inside inputs only shortcuts with mod fire. | string | false | "mod+k" |
open / defaultOpen / onOpenChangePalette state. | boolean | — |
CommandPalette
| Prop | Type | Default |
|---|---|---|
sizeDialog width. | "md" | "lg" | "lg" |
placeholderInput placeholder. | string | — |
recentsRecently used commands first (localStorage ui-cmd-recent, 8 ids). | boolean | true |
footerHint bar: ↑↓ navigate · ↵ select · ⌫ back · esc close. | boolean | true |
groupOrderGroup order for the empty query. | string[] | — |
labelsOverride built-in strings. | Partial<CommandLabels> | — |
CommandAction
| Prop | Type | Default |
|---|---|---|
idModule-prefixed and unique: "cms.post.new". | string | — |
title / subtitleRow text; both are searched. | string | — |
group"Go to", "Posts"… | string | "Actions" |
iconLeading icon. | LucideIcon | ReactNode | — |
keywordsSynonyms. | string[] | — |
shortcutWith global: true it works while the palette is closed. | string | string[] | — |
hrefNavigates through the app router. | string | — |
performRuns the action; a promise keeps the palette open until it settles. | (ctx) => void | Promise | — |
childrenOpens a sub-page. | CommandAction[] | () => Promise<CommandAction[]> | — |
permissionHidden unless can(permission). | string | string[] | — |
whenContextual visibility. | (ctx) => boolean | — |
priorityHigher first among equal matches. | number | — |
appApp badge in multi-app shells. | string | — |
Hooks
| Prop | Type | Default |
|---|---|---|
useRegisterCommands(actions, deps?)Adds commands while mounted; ref-counted and StrictMode-safe. | void | — |
useCommandSource(source)Adds an async source while mounted. | void | — |
useCommandPalette()Control the palette from anywhere. | { open(pageId?), close, toggle, isOpen, available } | — |
createCommandRegistry({ actions, sources })A store (useSyncExternalStore) to share between providers. | CommandRegistry | — |