Components / Overlays
CommandPalette
A search box over every command in the product. Press Ctrl+K (Command+K on a Mac), type a few letters, press Enter. It is the fastest way to reach an action without hunting through menus.
When to useLink to "When to use"
- Products with many actions spread across menus and panels: inspectors, editors, database tools.
Use something else when:
UsageLink to "Usage"
import { CommandPalette } from "@arshad-shah/cynosure";
<CommandPalette
commands={[
{ id: "save", label: "Save file", group: "File", shortcut: ["Ctrl", "S"], keywords: ["write", "disk"] },
{ id: "preview", label: "Toggle preview", group: "View" },
]}
onRun={(id) => actions[id]()}
/>Mount it once near the root. It listens for its shortcut (mod+k by default) anywhere on the page, shadow roots included. A command's shortcut is only shown in the row; bind those keys with useHotkey.
Finding commandsLink to "Finding commands"
Every typed word must appear in the label or the keywords, in any order, and commands whose label starts with the first word come first. Each typed word is marked where it appears in a label (HighlightedText); the option is still named by its whole label. Before anything is typed, the commands run most recently come first under "Recent".
Before anything is typed, commands are listed under their group headings. Search results are one flat list in rank order, so each row shows its group as a small Badge between the label and the shortcut; recent commands, which mix groups, carry the tag too.
Your own searchLink to "Your own search"
filter(command, query) replaces the built-in search, for an app with its own fuzzy matcher. It is called for each command while there is a query (trimmed), and answers with a match, true, or null:
<CommandPalette commands={commands} onRun={run} filter={(command, query) => fuzzyMatch(query, command.label)} />- A match
{ score, positions }keeps the command. Lower scores come first, as fuzzy matchers score them; ties, and matches without a score, keep the order ofcommands.positionsare the indices of the matched characters in the label, and exactly those are marked. truekeeps the command, unmarked.nullorfalseleaves it out.
Shortcuts with useHotkeyLink to "Shortcuts with useHotkey"
import { useHotkey } from "@arshad-shah/cynosure";
useHotkey("mod+s", save);
useHotkey("/", focusSearch); // plain keys are ignored while typing in a fieldShortcuts with Ctrl, Command or Alt work everywhere, text fields included. Plain keys are ignored in fields, so "/" still types a slash. Add data-cy-hotkeys="off" to a subtree (a code editor with its own bindings) to opt it out.
PropsLink to "Props"
| Prop | What it does | Type | Default |
|---|---|---|---|
commandsRequired | The commands to search and run. | Command[] | |
onRunRequired | Called with the chosen command's id; the palette then closes. | (id: string) => void | |
open | Controlled: whether the palette is open. | boolean | |
defaultOpen | Open at first, when uncontrolled. | boolean | |
onOpenChange | Called when the palette opens or closes (shortcut, Escape, a press outside, running a command), with the new state. | ((open: boolean) => void) | |
shortcut | Global shortcut that toggles the palette (mod is Command on Apple platforms, else Control). false: none. | string | false | |
filter | Your own search, called for each command while there is a query: return a CommandMatch ({ score, positions }, as fuzzy matchers return it), true to keep the command unmarked, or null/false to leave it out. Default: every word of the query in the label or keywords, label prefixes first, the words marked. | ((command: Command, query: string) => CommandMatch | boolean | null | undefined) | |
recentLimit | How many recently run commands to list before you type (default 5, 0 for none). | number | |
labels | Replace the built-in English text: the palette's name, the placeholder, the empty note and the recent heading. | Partial<CommandPaletteLabels> | |
className | Added to the panel, for layout. | string | |
style | Layout only, applied to the panel. | CSSProperties |
Generated from the type definitions in @arshad-shah/cynosure 0.5.0.
Behaviour and accessibilityLink to "Behaviour and accessibility"
| Input | Result |
|---|---|
| Control / Command + K | Opens or closes it from anywhere |
| Typing | Filters the commands into one flat list, each tagged with its group |
| Down arrow / Up arrow | Next / previous command, wrapping around; disabled ones are skipped |
| Enter or a click | Runs the command and closes |
| Escape or the backdrop | Closes; focus returns to where it was |
- Roles: a modal
dialognamed bylabels.title, holding acomboboxsearch field and alistboxofoptions in namedgroups (search results are one unnamed group). A row's group tag is part of its name. The active command isaria-activedescendant, so focus stays in the search field. - Fresh each time: the search field is empty whenever it opens.
- Shadow DOM: works inside shadow roots (extensions), including the shortcut.
TouchLink to "Touch"
Command rows are at least 44px tall on coarse pointers. On narrow screens the panel spans the width.
ThemingLink to "Theming"
Tokens: --cy-command-palette-width, --cy-command-palette-offset (distance from the top) and --cy-command-palette-list-max-height. The backdrop uses --cy-dialog-scrim.
RelatedLink to "Related"
These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.