// preview in
saved for every page

CommandPalette

A search box in a dialog that finds and runs commands, pages and records by name. It speeds up people who use the app every day; everything in it also needs a visible path.

Built on Base UIPattern WAI-ARIA Dialog (Modal) + ComboboxClient componentSource ↗

Installation

Set up Camaleo once (Installation), then import what you need. It renders on the client.

import { CommandPalette, CommandPaletteTrigger, CommandPaletteContent, CommandPaletteInput, CommandPaletteList, CommandPaletteGroup, CommandPaletteItem, CommandPaletteEmpty, CommandPaletteFooter } from "@camaleo/react";

Anatomy

CommandPaletteContent renders the backdrop and the dialog in a portal. Focus stays in the search; the arrow keys move a highlight through the list with aria-activedescendant.

Examples

Every example is a real file you can copy, in the skin, mode and brand from the bar above. Each one starts closed: open it, type, use the arrows and Enter, then Esc. The palette doesn't filter on its own. Keep the query in state, render only the commands that match, and give CommandPaletteList a key={query}, so the arrow keys follow the new order.

minimal · light · #3fa34d
Acme Finance
WEB-142Fix the checkout total on mobileor press CtrlK
Due 11/14/2026 · Assigned to Ana Ribeiro

Ctrl+K and command shortcuts

Press Ctrl+K anywhere on this page. The button stays as the visible way in, and each command shows its own shortcut so people learn it.

Website redesign
Pick a page or an action.

Groups: Navigation, Actions, Recent

Headings help people scan a long list. A group with no matches disappears with its heading, and the highlight scrolls into view.

Account settings
Try “receipt” or “add user”.

Keywords and synonyms

Type "receipt" or "add user". People search with their own words, so match keywords too and say which one matched.

Café Aurora · Admin
Open it and type “payroll”: this store has no payroll.

Empty state

Repeat what was searched and suggest what to try. The query stays in the box so it's easy to fix.

Leads & Customers

Results from the server

Type a name. While the request runs, the list has aria-busy and the footer says "Searching…"; a newer search makes the old one stale.

Notes

Pages inside the palette

"Change theme…" opens a page of options. Esc or Backspace in an empty search goes back one level before closing.

Venue contract for the 12/05 meetupCarla Mendes · 10:42 AM

Counts and results announced

The footer count is a polite status, read when typing pauses. After a command runs, a status outside the palette says what happened.

October travel expenses$1,284.50 · 12 receipts

A command you can't run

Keep it in the list with aria-disabled and say why. People find it, learn who can do it, and Enter does nothing.

In context

These are whole pieces of UI you can copy, in the skin you picked.

Acme
Overview
Revenue$48,21012.4%vs. September
Orders1,3273.1%vs. September
Dashboard header searchCommandPalette · Button · Avatar · Stat · Card
Acme Pay docs
GuidesAuthentication

Send your API key in the Authorization header of every request. Keys starting with sk_test_ only work in the sandbox.

Docs site searchCommandPalette · Button · Kbd · Card
// src/app/page.tsx
Try “chkform” or “fmtcur”: letters in order find the file.
Editor: Go to fileCommandPalette · Tabs · Button · Card

Guidelines

Invoices
DoA shortcut to things already on the page.

Creating and exporting have their own buttons. The palette is the faster way for people who know what they want.

Invoices
Don’tActions that live only in the palette.

Nobody browses a search box. If "Create invoice" isn't on the page, most people never find it.

Invoices
DoShort labels that start with a verb.

"Send payment reminder" says what will happen, and the first word is what people type.

Invoices
Don’tNouns and long sentences.

"Invoice" could open, create or delete one. A sentence gets cut off and is hard to match.

Props

PropTypeDefaultDescription
shortcutbooleantrueListen for Ctrl+K (⌘K on a Mac) anywhere on the page to open and close the palette. Turn it off when the page has more than one palette.
openboolean—Whether the palette is open. Use it with onOpenChange to control the state.
defaultOpenbooleanfalseWhether it starts open. Leave it off: a palette should open when people ask for it.
modal"trap-focus" | booleantruetrue traps focus and hides the page behind from screen readers. Keep the default.
onOpenChange(open, eventDetails) => void—Called when it opens or closes. eventDetails.reason says why, for example escape-key.

CommandPaletteContent, CommandPaletteList, CommandPaletteEmpty and CommandPaletteFooter take the props of their div; pass aria-label to the content and the list. CommandPaletteInput takes the props of an input, including value, onChange and aria-label. CommandPaletteTrigger takes render.

Each command is a CommandPaletteItem:

PropTypeDefaultDescription
valuestring—Written to data-value, for your own filtering or tests. The palette does not filter by it.
iconReactNode—Icon at the start, hidden from screen readers.
shortcutReactNode—Shown at the end, e.g. Kbd keys or a hint. Display only: wire the shortcut yourself.
onSelect(() => void)—Runs the command, on click or on Enter while the item is active.
disabledbooleanfalseShown but skipped by the arrow keys, and onSelect doesn't run. Say why in the label.

onSelect runs the command, on a click or on Enter while the item is highlighted. It also takes the props of its div, like aria-disabled, aria-keyshortcuts and onMouseDown. CommandPaletteGroup takes label, its visible heading.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the palette itself.

Attributes

data-active · aria-selected="true"on the highlighted command
aria-disabled="true"a command that can't run; shown muted
data-valuethe item's value prop
data-open · data-closedon the dialog and the backdrop

Tokens it reads

Color

--cml-accent--cml-accent-fg--cml-border-control--cml-border-subtle--cml-dialog-bg--cml-dialog-border--cml-fg--cml-fg-secondary--cml-radius-surface--cml-shadow-surface--cml-surface-raised

Shape & size

--cml-border-width--cml-popover-border-width--cml-radius-control--cml-radius-popover

Type & motion

--cml-font-body--cml-font-label

This component only

--cml-cmd-active-bg--cml-cmd-active-fg--cml-cmd-border--cml-cmd-footer-border--cml-cmd-header-border
/* a taller list for the file finder */
.editor [data-slot="command-palette-list"] {
  max-height: 24rem;
}

Accessibility

Ctrl + K / ⌘ + KOpens the palette from anywhere on the page, and closes it when it's open. Only with the shortcut prop on, and not while typing in another text field, where editors use Ctrl+K for links.
Enter / SpaceOn the trigger, opens the palette with focus in the search.
↓ / ↑Moves the highlight to the next or previous command, wrapping at the ends. Focus stays in the search.
EnterRuns the highlighted command.
EscCloses the palette and returns focus to the element that had it. It doesn't clear the search first.
TabStays in the search: it's the only control in the dialog.
Was this page helpful? · Edit this page on GitHub