Command Palette
Accessible, unstyled command palette built on the command router, Dialog, and composite navigation.
|
|
| Package |
@vizejs/ui/command-palette |
| Maturity |
stable |
| Own the source |
vize lib pull command-palette |
| Requires |
collection, command, composite-navigation, context, controllable-state, dialog, id, live-region, shortcut |
| Aliases |
command palette, command menu, cmdk, spotlight, quick open |
| Covers |
WAI-ARIA Combobox with listbox popup, cmdk, Ark UI Combobox, VS Code Command Palette |
Usage
import { CommandPalette, CommandPaletteRoot, CommandPaletteDialog, CommandPaletteEmpty, CommandPaletteGroup, CommandPaletteInput, CommandPaletteItem, CommandPaletteList, CommandPaletteLoading } from "@vizejs/ui/command-palette";
Or copy the source into your project with vize lib pull command-palette (see Source Distribution).
API
CommandPalette<Id extends string = string>
Source: src/families/overlays/command-palette/command-palette-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned base id. null and undefined select a deterministic fallback. |
open |
boolean |
undefined |
Controlled visibility of the results list (aria-expanded on the input). |
defaultOpen |
boolean |
true |
Initial uncontrolled results visibility. |
search |
string |
undefined |
Controlled search text. undefined selects uncontrolled behavior. |
defaultSearch |
string |
"" |
Initial uncontrolled search text. |
router |
CommandRouter<Id> |
undefined |
Command router whose commands items can run and whose metadata the default slot receives as commands. |
filter |
CommandPaletteFilter |
defaultCommandPaletteFilter |
Item scorer. 0 hides an item. The default ranks exact, prefix, word-prefix, substring, and subsequence matches. |
shouldFilter |
boolean |
true |
Filter items locally. Set false when results are already filtered, for example by a server search. |
loading |
boolean |
false |
Results are loading; the list reports aria-busy. |
loop |
boolean |
true |
Wrap arrow-key navigation at the first and last item. |
recent |
readonly Id[] |
undefined |
Controlled most-recent-first command ids. |
defaultRecent |
readonly Id[] |
[] |
Initial uncontrolled recent command ids. |
recentLimit |
number |
5 |
Maximum number of recent command ids kept. |
resultsLabel |
CommandPaletteResultsLabel |
defaultCommandPaletteResultsLabel |
Live-region announcement for the visible result count. |
Events
| Event |
Payload |
Description |
update:open |
[value: boolean] |
Fired when results visibility requests a new controlled value. |
update:search |
[value: string] |
Fired when the search text requests a new controlled value. |
update:recent |
[value: readonly Id[]] |
Fired when running a router command updates the recent list. |
select |
[commandId: Id | null, nativeEvent: Event | null] |
Fired after an item was selected; commandId is null for plain items. |
Slots
| Slot |
Slot props |
Description |
default |
CommandPaletteSlotState<Id> |
Palette parts. Receives search, result, and router command state. |
Exposed
| Member |
Type |
Description |
activeItemId |
— |
|
focusInput |
— |
|
id |
— |
|
listId |
— |
|
open |
— |
|
resultCount |
— |
|
search |
— |
|
selectActive |
— |
|
setOpen |
— |
|
setSearch |
— |
|
CommandPaletteRoot<Id extends string = string>
Source: src/families/overlays/command-palette/command-palette-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned base id. null and undefined select a deterministic fallback. |
open |
boolean |
undefined |
Controlled visibility of the results list (aria-expanded on the input). |
defaultOpen |
boolean |
true |
Initial uncontrolled results visibility. |
search |
string |
undefined |
Controlled search text. undefined selects uncontrolled behavior. |
defaultSearch |
string |
"" |
Initial uncontrolled search text. |
router |
CommandRouter<Id> |
undefined |
Command router whose commands items can run and whose metadata the default slot receives as commands. |
filter |
CommandPaletteFilter |
defaultCommandPaletteFilter |
Item scorer. 0 hides an item. The default ranks exact, prefix, word-prefix, substring, and subsequence matches. |
shouldFilter |
boolean |
true |
Filter items locally. Set false when results are already filtered, for example by a server search. |
loading |
boolean |
false |
Results are loading; the list reports aria-busy. |
loop |
boolean |
true |
Wrap arrow-key navigation at the first and last item. |
recent |
readonly Id[] |
undefined |
Controlled most-recent-first command ids. |
defaultRecent |
readonly Id[] |
[] |
Initial uncontrolled recent command ids. |
recentLimit |
number |
5 |
Maximum number of recent command ids kept. |
resultsLabel |
CommandPaletteResultsLabel |
defaultCommandPaletteResultsLabel |
Live-region announcement for the visible result count. |
Events
| Event |
Payload |
Description |
update:open |
[value: boolean] |
Fired when results visibility requests a new controlled value. |
update:search |
[value: string] |
Fired when the search text requests a new controlled value. |
update:recent |
[value: readonly Id[]] |
Fired when running a router command updates the recent list. |
select |
[commandId: Id | null, nativeEvent: Event | null] |
Fired after an item was selected; commandId is null for plain items. |
Slots
| Slot |
Slot props |
Description |
default |
CommandPaletteSlotState<Id> |
Palette parts. Receives search, result, and router command state. |
Exposed
| Member |
Type |
Description |
id |
string |
Root-owned base id. |
listId |
string |
Id of the rendered listbox. |
open |
boolean |
Whether results are showing. |
search |
string |
Current search text. |
resultCount |
number |
Number of visible items. |
activeItemId |
string | null |
Id of the active item, or null. |
setSearch |
(value: string) => boolean |
Replace the search text and report whether it changed. |
setOpen |
(value: boolean) => boolean |
Request a specific open value and report whether it changed. |
selectActive |
(event?: Event | null) => boolean |
Select the active item as if Enter was pressed. Returns whether an item was selected. |
focusInput |
(options?: FocusOptions) => void |
Focus the search input. |
CommandPaletteDialog
Source: src/families/overlays/command-palette/command-palette-dialog.vue
Props
| Prop |
Type |
Default |
Description |
open |
boolean |
undefined |
Controlled dialog visibility. undefined selects uncontrolled behavior. |
defaultOpen |
boolean |
false |
Initial uncontrolled dialog visibility. |
shortcut |
string | null |
"Mod+K" |
Global shortcut that toggles the dialog, resolved per platform (Mod is Command on Apple platforms and Control elsewhere). null disables it. |
closeOnSelect |
boolean |
true |
Close the dialog after an item is selected. |
ariaLabel |
string |
"Command palette" |
Accessible name of the dialog. |
to |
string | HTMLElement |
"body" |
CSS selector or element the dialog layer is moved into. |
portalDisabled |
boolean |
false |
Render the dialog in place instead of teleporting it. |
Events
| Event |
Payload |
Description |
update:open |
[value: boolean] |
Fired when the dialog requests a controlled open value. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly open: boolean; readonly close: ( |
A CommandPaletteRoot and its parts. Receives the dialog state and a close function. |
Exposed
| Member |
Type |
Description |
open |
boolean |
Whether the dialog is open. |
setOpen |
(value: boolean) => boolean |
Request a specific open value and report whether it changed. |
toggle |
() => boolean |
Toggle the dialog. |
CommandPaletteEmpty
Source: src/families/overlays/command-palette/command-palette-empty.vue
Slots
| Slot |
Slot props |
Description |
default |
{ readonly search: string } |
Fallback shown when no item matches and nothing is loading. Receives the search. |
CommandPaletteGroup
Source: src/families/overlays/command-palette/command-palette-group.vue
Props
| Prop |
Type |
Default |
Description |
heading (required) |
string |
required |
Visible group heading, also used as the group's accessible name. |
forceMount |
boolean |
false |
Keep the group visible even when no item matches the search. |
Slots
| Slot |
Slot props |
Description |
default |
CommandPaletteGroupSlotState |
Group items. Receives the heading and visible item count. |
heading |
CommandPaletteGroupSlotState |
Custom heading contents. Receives the heading and visible item count. |
Source: src/families/overlays/command-palette/command-palette-input.vue
Props
| Prop |
Type |
Default |
Description |
placeholder |
string |
undefined |
Placeholder text shown while the search is empty. |
ariaLabel |
string |
"Search commands" |
Accessible name of the search combobox. |
autofocus |
boolean |
false |
Move focus into the input after mount. |
disabled |
boolean |
false |
Disable the search input. |
Events
| Event |
Payload |
Description |
keydown |
[nativeEvent: KeyboardEvent] |
Fired before palette key handling. Call preventDefault() to skip it. |
Exposed
| Member |
Type |
Description |
element |
HTMLInputElement | null |
Rendered input element. |
focus |
(options?: FocusOptions) => void |
Move focus to the input. |
CommandPaletteItem<Value = undefined>
Source: src/families/overlays/command-palette/command-palette-item.vue
Props
| Prop |
Type |
Default |
Description |
value |
Value |
undefined |
Consumer data handed back through the select event. |
textValue |
string |
undefined |
Searchable label. undefined uses the router command title, then the rendered text after mount. |
keywords |
readonly string[] |
[] |
Extra search terms. Router command keywords are appended. |
command |
string |
undefined |
Router command id run with source "palette" when the item is selected. |
shortcut |
string |
undefined |
Keyboard shortcut advertised through aria-keyshortcuts, for example "Control+K". |
disabled |
boolean |
false |
Refuse selection and skip the item during keyboard navigation. |
forceMount |
boolean |
false |
Keep the item visible whatever the search. |
Events
| Event |
Payload |
Description |
select |
[value: Value | undefined, nativeEvent: Event | null] |
Fired when the item is selected by click, Enter, or select(). |
Slots
| Slot |
Slot props |
Description |
default |
CommandPaletteItemSlotState |
Item contents. Receives active, disabled, and label state. |
Exposed
| Member |
Type |
Description |
active |
boolean |
Whether this item is the active descendant. |
disabled |
boolean |
Whether selection is refused. |
state |
CommandPaletteItemState |
Stable state token for styling and tests. |
textValue |
string |
Searchable label of the item. |
shortcut |
string | null |
Keyboard shortcut advertised through aria-keyshortcuts, or null. |
id |
string |
Stable item id used by aria-activedescendant. |
visible |
boolean |
Whether the current search keeps the item visible. |
element |
HTMLDivElement | null |
Rendered option element. |
select |
(event?: Event | null) => boolean |
Select this item. Returns whether selection ran. |
CommandPaletteList
Source: src/families/overlays/command-palette/command-palette-list.vue
Props
| Prop |
Type |
Default |
Description |
ariaLabel |
string |
"Commands" |
Accessible name of the listbox. |
Slots
| Slot |
Slot props |
Description |
default |
Omit<CommandPaletteSlotState, "recentCommands"> |
Items, groups, empty, and loading parts. |
Exposed
| Member |
Type |
Description |
element |
HTMLDivElement | null |
Rendered listbox element. |
CommandPaletteLoading
Source: src/families/overlays/command-palette/command-palette-loading.vue
Props
| Prop |
Type |
Default |
Description |
label |
string |
"Loading results" |
Accessible name of the loading indicator. |
Slots
| Slot |
Slot props |
Description |
default |
— |
Loading indicator contents. |
Behavior
Normative behavior for @vizejs/ui/command-palette, an APG combobox with a listbox popup
built on the command router, collection + composite-navigation (active descendant),
live-region, shortcut, and the Dialog parts. Every row names its proving test.
| State x input |
Observable outcome |
Proven by |
| any render |
The input is role="combobox" with aria-autocomplete="list", aria-expanded, aria-controls to the listbox, and aria-activedescendant on the first enabled option. |
renders combobox and listbox semantics with an active descendant |
| options and groups |
Options are role="option" with aria-selected for the active one, aria-disabled, and aria-keyshortcuts; groups are role="group" labelled by their heading. |
renders combobox and listbox semantics with an active descendant |
| typing in the input |
Items are scored against label and keywords; non-matching items and empty groups get hidden; the first visible option becomes active; update:search fires. |
typing filters items and groups, resets the active item, and announces the count |
| search changes after mount |
A polite live region announces the visible result count (resultsLabel). |
typing filters items and groups, resets the active item, and announces the count |
| no visible results, not loading |
CommandPaletteEmpty is shown and the listbox reports data-empty. |
typing filters items and groups, resets the active item, and announces the count |
| ArrowDown / ArrowUp / Home / End |
The active option moves, skipping disabled and hidden options, wrapping when loop. |
arrow keys, Home, and End move the active option and skip disabled ones |
| Enter |
The active option is selected: item select(value, event), root select(commandId, event); composing (IME) keystrokes are ignored. |
Enter selects the active item, IME composition is ignored, and Escape clears the search |
| Escape |
A non-empty search is cleared and the key is consumed; an empty search lets Escape reach an enclosing dialog. |
Enter selects the active item, IME composition is ignored, and Escape clears the search |
| pointer over / click on an option |
pointermove activates it; mousedown is prevented to keep focus in the input; click selects unless disabled. |
pointer movement activates options and clicks select without stealing focus |
| router commands |
The root slot receives filtered commands; items with command take its title/keywords, reflect when as disabled, run with source "palette", and update recent. |
router commands render through the slot, run with the palette source, and track recents |
shouldFilter=false, custom filter, loading, controlled search |
Local filtering is skipped, custom scores decide visibility, the listbox is aria-busy with the loading part shown and empty hidden, and controlled search waits for the parent. |
shouldFilter=false, custom filters, loading, and controlled search are honored |
closed palette (open=false) |
The listbox is hidden, aria-expanded="false", no active descendant; ArrowDown requests update:open(true). |
closed palettes hide the list and arrows reopen it |
CommandPaletteDialog, Mod+K |
The global shortcut toggles the dialog (Command on Apple, Control elsewhere); a selection closes it when closeOnSelect; shortcut=null disables. |
the dialog toggles with Mod+K and closes after a selection |
| default filter |
Exact > prefix > word prefix > substring > subsequence; case and diacritics are ignored; keywords count slightly less. |
default filter ranks exact, prefix, word, substring, and subsequence matches |
| parts outside the root |
Mounting throws VIZE_UI_CONTEXT_MISSING. |
palette parts require a root provider |
| SSR |
Isolated requests render byte-identical markup; the closed dialog renders no content; the shortcut listener attaches only after mount. |
renders byte-identical palette markup across isolated SSR requests |
| hydration |
Hydration reuses server nodes with zero warnings and then activates the first visible option. |
hydrates without mismatches and activates the first visible option |
| public types |
Router id unions flow into recent ids and select; item value types the item select payload. |
src/families/overlays/command-palette/command-palette.types.test-d.ts |
Components
| Component |
Contract |
command-palette-root.vue |
Generic over router command ids; owns search, open, recent, scoring, active option, and the result announcer. |
command-palette-input.vue |
Combobox input: typing, arrows, Home/End, Enter, Escape, IME-safe. |
command-palette-list.vue |
Listbox popup with aria-busy and data-empty. |
command-palette-group.vue |
Labelled option group hidden when it has no visible options (unless forceMount). |
command-palette-item.vue |
Generic over value; option with keywords, router command, shortcut, and select. |
command-palette-empty.vue |
Fallback shown when nothing matches and nothing is loading. |
command-palette-loading.vue |
progressbar shown while loading. |
command-palette-dialog.vue |
Dialog composition with the Mod+K toggle; closes after selection. |
Parts And Data
| Target |
Public contract |
| Root |
data-vize-ui="command-palette-root", part="root", data-state, data-loading |
| Input |
data-vize-ui="command-palette-input", part="input", data-state |
| List |
data-vize-ui="command-palette-list", part="list", data-state, data-empty |
| Group |
data-vize-ui="command-palette-group", heading part="group-heading", data-empty |
| Item |
data-vize-ui="command-palette-item", part="item", data-state, data-command |
| Dialog |
data-vize-ui="command-palette-dialog", part="dialog", data-state, data-shortcut |
CommandPalette ships no stylesheet; the announcer is visually hidden with inline styles.