Skip to content

ComponentsOverlays

Command Palette

A keyboard-driven command menu in a modal, filtered as you type. Built on React Aria's Autocomplete and Menu, with sections, shortcuts, icons, links, disabled commands and a custom empty state; accent- and case-insensitive matching out of the box.

React AriaSource

Installation

pnpm dlx shadcn@latest add @desyne/command-palette

The CLI installs dependencies and any other components this one uses.

Usage

tsx
import {
  CommandItem,
  CommandPalette,
  CommandSection,
  CommandSeparator,
  CommandShortcut,
} from "@/components/ui/command-palette";
tsx
const [isOpen, setOpen] = useState(false);

<CommandPalette
  isOpen={isOpen}
  onOpenChange={setOpen}
  onAction={(key) => run(key)}
>
  <CommandItem id="new-project">New project</CommandItem>
  <CommandItem id="invite">Invite teammate</CommandItem>
</CommandPalette>

Control the palette with isOpen and onOpenChange, and bind the ⌘+K shortcut yourself with a keydown listener (see the demo's code).

The palette closes itself after a command runs: once onAction (or an item's own onAction) has been called, it calls onOpenChange(false). Links (href items) close it too. Pass closeOnAction={false} to keep it open, for example for multi-step commands, and close it yourself with setOpen(false) when you're done.

When to use

  • Command Palette — a global, searchable list of actions and destinations, usually on ⌘+K. Also good for any "pick one from many" step, like assigning a teammate.
  • Menu — a short, contextual list of actions attached to a button.
  • Combo Box — a searchable form field that keeps a value.
  • Search Field — searching content on the page rather than running commands.

Anatomy

tsx
<CommandPalette>                 {/* overlay + modal + dialog + search input + menu */}
  <CommandSection title="…">     {/* optional group with a heading */}
    <CommandItem>                {/* a command */}
      <Icon />
      Label
      <CommandShortcut />        {/* keyboard hint */}
    </CommandItem>
  </CommandSection>
  <CommandSeparator />
</CommandPalette>
PartRendersNotes
CommandPaletteModalOverlay › Modal › Dialog › AutocompleteBackdrop, a panel near the top of the screen (pt-[15vh]), a search input and a role="menu" list that scrolls after 320px.
Search inputSearchField › <input type="search">Auto-focused, with aria-label="Search commands" and a search icon.
CommandItem<div role="menuitem">A command. Same component as MenuItem: variant, href, isDisabled and render props all work.
CommandSection<section role="group">Groups items under an optional title. Hidden when none of its items match.
CommandSeparator<hr>Divider between sections.
CommandShortcut<kbd>Right-aligned shortcut hint. The palette doesn't bind it.
Empty state<div>emptyMessage, shown when nothing matches.

Examples

Dynamic items

Pass items and a render function instead of static children. Each item needs an id; onAction receives it. Only the items that match the query are rendered.

Rich items

Put React Aria's Text with slot="label" and slot="description" inside a CommandItem for two-line results. The description is announced separately, and filtering still uses textValue.

Search keywords

Filtering matches the query anywhere in an item's textValue, ignoring case and accents. Add synonyms to textValue so "dark" finds Appearance or "2fa" finds Security. The item's accessible name still comes from its visible content.

Try “dark”, “2fa” or “timezone”

Give an item an href to navigate. Same-page anchors, external URLs with target="_blank", and routes through React Aria's RouterProvider all work.

Disabled commands

disabledKeys keeps commands visible but not selectable, and keyboard navigation skips them. Say why, for example with a hint on the item.

Empty state

emptyMessage accepts any node. Use it to suggest what to try next. placeholder sets the input's hint, and aria-label names the dialog (it defaults to "Command palette").

Recipes

The classic ⌘+K palette: a search-style trigger button with a Kbd hint, a global shortcut, recent items, actions with shortcuts and navigation. className="max-w-xl" widens the panel.

Assign a teammate

A palette used as a picker: people with Avatars, searchable by name or email through textValue, that sets the assignee on an issue card.

ENG-512

Retry failed webhook deliveries

High
Unassigned

Theme switcher

A narrow palette (max-w-sm) that switches the theme, with a check on the current option.

Accessibility

  • The palette is a modal dialog: focus is trapped, the page is hidden from screen readers, and focus returns to the previously focused element on close.
  • Focus stays in the search input while ↑ / ↓ move a virtual focus through the results, so users can keep typing. The highlighted command is announced as it changes.
  • Name the dialog with aria-label when it has a specific purpose ("Assign issue"); the default is "Command palette".
  • Commands are menuitems with their text from textValue; section titles label their groups.
  • Shortcuts shown with CommandShortcut are hints only. Register the keys with your own handler.

Keyboard

KeyAction
Any characterFilters the commands
↓ / ↑Moves the highlight through the results
Home / EndHighlights the first / last result
Page Up / Page DownMoves the highlight by a page
EnterRuns the highlighted command
EscClears the query, or closes the palette when the query is empty

Styling

Data attributes

On each CommandItem, the same attributes as MenuItem: data-focused for the highlighted result, data-disabled, data-hovered, data-pressed and data-variant. The panel has data-entering / data-exiting during its fade and zoom.

Slots

data-slotElement
command-palette-overlayBackdrop
command-palettePanel
menu-item, menu-section, menu-separator, menu-shortcutItems and their parts

Customizing

  • className styles the panel. It's w-full max-w-lg by default: use max-w-xl for a wider palette or max-w-sm for a focused picker.
  • The result list is capped at max-h-80 and scrolls; icons in items are sized and muted like in Menu.
  • The backdrop reuses overlayStyles from Dialog.

API Reference

CommandPalette

Prop

Type

Also accepts the other props of React Aria's ModalOverlay. Filtering is provided by Autocomplete.

CommandItem / CommandSection / CommandSeparator / CommandShortcut

Re-exports of MenuItem, MenuSection, MenuSeparator and MenuShortcut. They accept the same props; CommandItem also takes textValue, which is what the query is matched against.

  • Menu — the same items in a dropdown.
  • Dialog — the modal the palette is built on.
  • Combo Box — a searchable field that keeps a value.
  • Kbd — show the shortcut that opens the palette.