Skip to content

Overlays

ICommandPalette ​

Every command in the app behind one shortcut. It opens on , filters as you type, and is driven entirely by keyboard.

Type bill in the palette above and Invoices survives: keywords adds search terms that never appear on screen, such as synonyms or a page's former name.

Flat commands ​

Groups are optional. A bare array is a single list, and entries written before or between groups keep their position.

The shortcut that opens it ​

hotkey defaults to mod+k, where mod is Command on Apple platforms and Control everywhere else. It is bound on the window, so it works wherever focus is.

vue
<ICommandPalette v-model:open="open" :items="commands" hotkey="mod+shift+p" />

<!-- Bind nothing; drive `open` yourself -->
<ICommandPalette v-model:open="open" :items="commands" :hotkey="null" />

The demos on this page pass :hotkey="null" so they cannot fight the site's own palette. Press anywhere on these docs to see the real one.

Recent commands ​

recent-key makes the palette remember the commands a reader picks and list the latest ones first, under "Recent", while the search is empty. They're stored in localStorage under that key, so give each palette its own.

vue
<ICommandPalette :items="commands" recent-key="app-command-palette" />

Shortcuts on a row ​

shortcut is display only — bind the chord yourself, where the command lives. Write it as spaced keys and each is rendered as its own kbd: mod n, g i, ⇧ ⌘ P.

Disabled commands ​

A command with disabled still appears, struck through and carrying aria-disabled, but cannot be chosen and is skipped by the arrow keys. That is Archive invoice in the first palette on this page.

Give a command an href and its row renders as an <a>, so middle-click, -click and "open in new tab" all work. onSelect still fires for a plain click.

ts
const command = { label: 'Documentation', href: '/docs', onSelect: () => track('help') }

Props ​

PropTypeDefaultDescription
items(CommandItem | CommandGroup)[]—Commands, optionally grouped
placeholderstring'Search commands…'Text in the field
emptyTextstring'No matching commands.'Shown when nothing matches
labelstring'Command palette'Accessible name for the dialog
hotkeystring | null'mod+k'Chord that opens it; null binds nothing
closeOnSelectbooleantrueClose once a command is chosen
recentKeystring—localStorage key for remembering recent commands; unset remembers nothing
recentLimitnumber5How many recent commands to keep
recentLabelstring'Recent'Heading over the recent commands
footerbooleantrueThe keyboard-hint row along the bottom
unstyledboolean—Drop built-in classes
classstring—Merged onto the panel
ui{ overlay?, content?, header?, icon?, input?, viewport?, group?, groupLabel?, item?, itemIcon?, itemLabel?, shortcut?, key?, empty?, footer? }—Per-element class overrides

v-model:open controls it. Nothing is rendered while it is closed.

Events and slots ​

EventPayloadWhen
selectCommandItemA command was chosen, alongside its own onSelect
SlotPropsWhen to use it
item{ item }Render a row yourself — a description line, a badge
empty{ query }Replace the no-results text
footer—Replace the hint row

Item shapes ​

ts
interface CommandItem {
  label: string
  /** Stable identity for the recent list; defaults to group and label. */
  id?: string
  icon?: IconLike
  /** Display only, split on spaces into separate keys. */
  shortcut?: string
  /** Extra search terms that never appear on screen. */
  keywords?: string[]
  href?: string
  disabled?: boolean
  onSelect?: () => void
}

interface CommandGroup {
  label: string
  items: CommandItem[]
}

A group whose commands all fail the filter is dropped, heading included.

The panel sits at 12vh rather than centred, so the field stays put as the list grows and shrinks.