Productivity Features
Recent commands
Recent commands are always tracked in memory for the current session and shown above all other commands when the palette opens with an empty query. When persistRecent: true (the default), the list is additionally written to localStorage so it survives reloads; setting persistRecent: false keeps recent working for the session without touching localStorage.
app.use(VCommandPalettePlugin, {
persistRecent: true,
maxRecent: 8, // keep at most 8 commands total
maxRecentPerGroup: 2, // at most 2 per group (0 = unlimited)
localStorageKey: 'myapp:recent',
})Recent commands are resolved at runtime — if a command is unregistered (e.g. its component unmounted), it is silently excluded from the recent list.
Pinned commands
Users can pin any command to a Pinned section shown above Recent in the empty-query view. Toggle a pin with $mod+P on the active item, by clicking the pin icon on the row (it appears as a ghost on hover / keyboard-active rows, and stays lit on pinned commands — clicking it never runs the command), or via the composable API. Pins persist to localStorage (<localStorageKey>:pinned) when persistRecent is on.
const { pin, unpin, togglePin, isPinned, getPinnedCommands, pinnedIds } = useCommandPalette()Frecency
With frecency: true, the palette tracks how often and how recently each command is executed and adds a bonus to its search score, so your most-used commands float to the top. Stats are kept in memory and (when persistRecent is on) persisted to localStorage under <localStorageKey>:frecency.
app.use(VCommandPalettePlugin, { frecency: true })The bonus combines frequency (run count) with recency (decays over ~30 days), and never hides a strong exact/prefix match — it only reorders comparable results.
Preview pane
Set preview to show a right-hand panel for the active command — great for details, docs, or thumbnails. It updates as the selection changes (it pairs naturally with the onHighlight option for async previews). On narrow screens the pane is hidden automatically.
Two sources fill the pane, in order:
- The
#previewslot —{ command }scope, full control over the markup. - The active command's
infofield (plain text or HTML) — rendered after the slot. Handy when you don't need a custom slot.
<CommandPalette preview>
<template #preview="{ command }">
<div v-if="command">
<h3>{{ command.label }}</h3>
<p>{{ command.description }}</p>
</div>
</template>
</CommandPalette>useRegisterCommands([
{
id: 'analytics',
label: 'Open Analytics',
info: '<p>Traffic, conversions and revenue charts.</p>', // text or HTML
perform: () => {},
},
])Security:
infois rendered withv-html. Only pass trusted/sanitised markup.
Toggling the pane
- A sidebar icon appears next to the theme switcher to expand/collapse the pane.
- The
previewHotkeyprop sets a keyboard toggle (default['$mod', 'i']→ ⌘/Ctrl + I; pass[]to disable). - Opening/closing animates the pane's width in sync with the dialog width, so the list stays a constant width and there's no jump; respects
prefers-reduced-motion.
The dialog only widens to --vcp-dialog-preview-width (default 860px) while the pane is expanded — when it's collapsed (or preview is off) the dialog returns to the normal --vcp-dialog-width (560px). The pane is --vcp-preview-width wide (default 300px); keep dialog-preview-width − dialog-width = preview-width for a perfectly steady list during the animation.
Secondary actions
A command can expose secondary actions (open, copy, delete, …). Press Tab on the active item to open the actions menu; arrows navigate, Enter runs, and Esc / Tab / Backspace (or the ‹ Back button in the header) returns to the list. Customise the menu with the #actions slot ({ command, run, activeIndex, close }).
useRegisterCommands([
{
id: 'export',
label: 'Export data',
perform: () => download(),
actions: [
{ id: 'copy', label: 'Copy as JSON', perform: () => copyJson() },
{ id: 'mail', label: 'Email export', shortcut: ['$mod', 'm'], perform: () => email() },
],
},
])Items with actions show a ⋯ affordance.
Multi-select
With selectable, the palette becomes a multi-picker: Enter (or click) toggles the active item, $mod+Enter submits. Selected rows show a checkbox.
<CommandPalette selectable @submit-selection="onPicked" />function onPicked(commands: Command[]) {
// do something with the chosen commands
}Mobile / touch
The palette is responsive out of the box: on viewports ≤ 640px the dialog goes full-width with larger (48px) touch targets, the preview pane is hidden, and hover styles are disabled on touch devices. Inside a nested palette/page, swipe right to go back.