Skip to content
Kura UI

Command Palette

beta

⌘K command palette for agent actions: fuzzy search, groups, recents, nested pages with async loading, and shortcut hints.

@kura-ui/react/command-paletteCopy page for agents.mdregistry.json

With a trigger

minimal

Agent actions, recents and nested pages

Controlled open state, ⌘K, recents, a nested “Switch agent…” page and an async “Run workflow…” page.

full
or pressControl K

Nothing run yet

Server-side search

onQueryChange fetches results into `items` while `loading` shows skeleton rows.

composition

Installation

npx shadcn@latest add https://kuro.abstergo.fyi/r/command-palette.json

Copies the source into components/kura/command-palette with its dependencies (kura-theme, kbd, kura-keys, use-controllable-state, use-hotkey, utils). Tokens come from the kura-theme item.

When to use it

Use it for

  • A global launcher for agent actions: run/stop an agent, switch agents, add context, change settings.
  • Navigating many commands or entities (files, threads, workflows) by typing.
  • Multi-step choices as nested pages (“Change theme…” → Light / Dark), including lists fetched on demand.

Reach for something else when

  • Commands typed inline inside a prompt — use slash-command-menu.
  • Choosing a model — use model-picker.
  • A handful of starter prompts in an empty chat — use prompt-suggestions.

Props

PropTypeDefaultDescription
items*readonly CommandPaletteItem[]—Items: { id, label, description?, icon?, group?, keywords?, shortcut?, onSelect?, children?, loadChildren?, placeholder?, disabled? }. children/loadChildren open a nested page.
openboolean—Controlled open state.
defaultOpenbooleanfalseInitial open state.
onOpenChange(open: boolean) => void—Open state changes.
hotkeyreadonly KeyName[] | null["mod", "k"]Global toggle shortcut (works in inputs). null disables it.
triggerReact.ReactElement—Element rendered as the dialog trigger, e.g. <CommandPaletteTrigger />.
recentstring[]—Controlled recent item ids (most recent first), shown as “Recent” when the query is empty.
defaultRecentstring[]—Initial recents when uncontrolled.
onRecentChange(ids: string[]) => void—Called when an item is used (persist it to localStorage if you like).
recentLimitnumber4Max recents shown.
onSelect(item: CommandPaletteItem) => void—Called after any leaf item runs (in addition to item.onSelect).
onQueryChange(query: string) => void—Every query change — fetch server results into `items` and toggle `loading`.
loadingbooleanfalseShow skeleton rows and aria-busy (root page). Nested pages with loadChildren handle this themselves.
placeholderstring"Search or run a command…"Search placeholder on the root page.
emptyMessagestring"No results"Shown when nothing matches.
labelstring"Command palette"Accessible dialog title (visually hidden).

All native attributes of the root element, className and ref pass through.

Anatomy

  1. CommandPaletteModal dialog surface (translucent overlay, origin-top pop). data-page = current nested page id.data-slot="command-palette"
  2. CommandPaletteSearchSearch row with breadcrumbs for nested pages.data-slot="command-palette-search"
  3. CommandPaletteGroupGroup heading (Recent first).data-slot="command-palette-group"
  4. CommandPaletteItemrole=option row: icon, label, description, shortcut or chevron. data-active, data-disabled.data-slot="command-palette-item"
  5. CommandPaletteLoadingSkeleton rows while loading.data-slot="command-palette-loading"
  6. CommandPaletteFooterResult count and the Enter action (Run / Open).data-slot="command-palette-footer"
  7. CommandPaletteTriggerSearch-field-styled button with the shortcut; pass it as `trigger`.data-slot="command-palette-trigger"

Accessibility

  • Role: dialog > combobox + listbox
  • A modal Radix dialog with a visually hidden title; focus moves to the search input on open and returns to the trigger on close.
  • The input is a combobox using aria-activedescendant, so screen readers read the highlighted option while focus stays in the field.
  • The listbox is aria-busy while loading; the footer's result count is a polite live region.
  • Nested pages are announced through the input's label (“Search Change theme…”) and shown as breadcrumbs.
  • Reduced motion: The dialog and overlay fade without scale; skeleton rows stop pulsing.
KeysAction
Mod+KToggle the palette (configurable)
ArrowDown / ArrowUpMove the highlight (wraps, skips disabled)
Home / EndFirst / last item (empty query)
EnterRun the item or open its page
Backspace (empty query) / EscapeGo back one page
Escape (root page)Close

Notes for agents

  • Mount one palette near the app root; it portals itself. Only one instance should bind ⌘K — pass hotkey={null} to others.
  • Use `children` for static sub-pages and `loadChildren` for fetched ones (the loading state is automatic).
  • Persist recents with recent/onRecentChange (e.g. localStorage); recents resolve ids anywhere in the item tree.
  • Shortcuts on items are display-only; bind them with useHotkey so they also work when the palette is closed.
  • scoreCommand(text, query) is exported if you need the same fuzzy ranking elsewhere.