Command Palette
A ⌘K search-and-act overlay - fuzzy search across grouped commands, keyboard-navigable, opened from anywhere.
Usage
Place SCommandPalette once (your root layout is a good spot) and
control it from anywhere with useCommandPalette() - the same
composable-driven pattern as useModal()/useSlideover(). Press
⌘K (or CtrlK) to open it too -
that shortcut is bound automatically, nothing to wire up yourself:
<script setup lang="ts">
const palette = useCommandPalette()
const groups = [
{
label: 'Actions',
items: [
{ label: 'New file', icon: 'hugeicons:file-add', shortcut: 'mod+n', hotkey: true, onSelect: () => {} },
{ label: 'New folder', icon: 'hugeicons:folder-add', onSelect: () => {} },
],
},
{
label: 'Navigation',
items: [
{ label: 'Go to settings', icon: 'hugeicons:settings-01', shortcut: 'mod+,', hotkey: true, onSelect: () => {} },
{ label: 'Go to profile', icon: 'hugeicons:user', onSelect: () => {} },
],
},
]
</script>
<template>
<SButton @click="palette.open()">
Open command palette
</SButton>
<SCommandPalette :groups="groups" />
</template>
items are an array of groups, same shape as
Dropdown/ContextMenu -
a separator (here, a small group label) between each group. Typing
filters every item with a lightweight fuzzy match (not a plain
substring check) - "nf" matches "New File" - and results re-rank live
as the query changes; an empty search keeps each group's own
authoring order rather than reshuffling the default view.
Item shortcuts
An item's own shortcut renders via Kbd as a
display hint. Add hotkey: true to bind it while the palette is open; the
item's normal selection behavior runs and the palette closes. Use mod to
show ⌘ on macOS and Ctrl on other platforms. The live example above includes
enabled shortcuts for creating a file and opening settings, plus items that
show no hint and therefore have no item-specific shortcut:
{ label: 'New file', shortcut: 'mod+n', hotkey: true, onSelect: () => {} }
Disabling the built-in shortcut
Set :shortcut="false" if you'd rather wire your own trigger (a menu
item, a different key combo) instead of the automatic
⌘K/CtrlK binding -
useCommandPalette().open() still works from anywhere either way.
<SCommandPalette :groups="groups" :shortcut="false" />
Keyboard interaction
↑/↓ move the highlighted result (wrapping past
either end, skipping disabled items), Enter runs the
highlighted item's onSelect and closes the palette, Esc
or an outside click closes it without running anything.
Custom :ui
To see exactly what you'd be overriding - the current default classes for every slot and variant - here's the palette's own theme file:
Props
| Prop | Type | Default |
|---|---|---|
groups | { label?: string; items: { label: string; icon?: string; shortcut?: string; hotkey?: boolean; disabled?: boolean; onSelect?: () => void }[] }[] | - |
open | boolean | - |
shortcut | boolean | true |
ui | Partial<Record<CommandPaletteSlot, string | object>> | - |
Multiple instances
Pass v-model:open if you need a second, independently-controlled palette
(a different groups list, scoped to some part of the app) instead of the
one shared instance:
<SCommandPalette v-model:open="open" :groups="scopedGroups" />
This instance stops reacting to useCommandPalette() entirely - its own
open/close/Cmd-K state is fully local. The default (no open prop)
stays wired to the shared singleton described above, which is what you
want for the single app-wide palette.
useCommandPalette()
| Member | Type | Description |
|---|---|---|
isOpen | Ref<boolean> | The shared open state |
open | () => void | Opens it |
close | () => void | Closes it |
toggle | () => void | Flips it |