API Reference
Command
interface Command<T = unknown> {
id: string // unique identifier
label: string // display text, searched by fuzzy engine
description?: string // subtitle shown below the label
icon?: Component | string // Vue component or emoji / string
keywords?: string[] // extra search terms
aliases?: string[] // alternate labels (same score as label match)
shortcut?: string[] // display-only hint: ['$mod', 'k']
disabled?: boolean // permanently unavailable
enabled?: () => boolean // dynamically disable — evaluated on each render
disabledReason?: string // tooltip shown when the command is disabled
badge?: string | { text: string; color?: string } // small label (e.g. "New", "Pro")
confirm?: string // prompt shown before execute
perform: () => void | Promise<void> // action; may be async
subCommands?: Command[] // opens a nested palette when selected
page?: CommandPage // opens a page with its own input/async search
actions?: CommandAction[] // secondary actions, opened with Tab
info?: string // text/HTML shown in the preview pane (v-html)
data?: T // type-safe payload (see Typed command data)
}icon field
Accepts an emoji string, a plain text string, or any Vue component:
import MyIcon from './MyIcon.vue'
{
icon: '🏠'
} // emoji string
{
icon: '⌘'
} // symbol string
{
icon: MyIcon
} // Vue component — rendered as <MyIcon />CommandAction
interface CommandAction {
id: string
label: string
icon?: Component | string
shortcut?: string[] // display-only hint
perform: () => void | Promise<void>
}A secondary action available on a command — see Secondary actions.
CommandPage
interface CommandPage {
placeholder?: string // input placeholder on the page
items?: Command[] // static items (empty query)
onSearch?: (query: string) => Command[] | Promise<Command[]> // query-driven results (debounced)
}Opened by a command instead of (or in addition to) running — see Command pages.
Typed command data
Attach an arbitrary, type-safe payload to commands via the generic Command<T> and its data field. useRegisterCommands / useRegisterGroup, fuzzySearch<T>, SearchResult<T> and SearchFn<T> all carry the type through, so you get full inference (and errors on mismatches). It defaults to unknown, so existing untyped usage is unaffected.
interface UserData {
id: number
email: string
}
useRegisterCommands<UserData>([
{
id: 'user-ada',
label: 'Ada Lovelace',
data: { id: 1, email: 'ada@example.com' }, // checked against UserData
perform: () => {},
},
])
// Standalone search keeps the type:
const results = fuzzySearch<UserData>('ada', commands)
results[0].command.data?.email // string | undefined// @ts-expect-error — data must match UserData
const bad: Command<UserData> = { id: 'x', label: 'X', data: { wrong: true }, perform: () => {} }Inside the
#item/#previewslots thecommandis typed asCommand(data: unknown) since the palette stores commands of mixed types — narrow with a cast or a type guard when you need the payload there.
SearchResult
interface SearchResult {
command: Command
score: number
matches: Array<[start: number, end: number]>
groupId?: string
parents?: Command[] // ancestor chain when the result is a nested sub-command
matchedField?: 'label' | 'description' | 'keyword' | 'alias' // which field won the score
matchedText?: string // matching keyword/alias text
}PaletteContext
The full injectable context, accessible in custom composables via inject(PALETTE_INJECT_KEY):
interface PaletteContext {
store: CommandStore
keyboard: KeyboardManager
isOpen: Ref<boolean>
query: Ref<string>
activeIndex: Ref<number>
history: Ref<HistoryEntry[]>
recentIds: Ref<string[]>
loadingCommandId: Ref<string | null>
results: ComputedRef<SearchResult[]>
persistRecent: boolean
maxRecent: number
maxRecentPerGroup: number
localStorageKey: string
onOpen?: () => void
onClose?: () => void
onError?: (err: unknown, command: Command) => void
}createCommandStore
(search?: SearchFn, searchNested?: boolean, scoreBonus?: (command: Command) => number, showDisabled?: boolean) => CommandStore
Low-level factory behind VCommandPalettePlugin and the testing utilities — registers/searches commands directly. Not normally needed: use the plugin or useCommandPalette() instead.
TypeScript types
All public types are exported from the package root:
import type {
Command,
CommandGroupType, // group definition — NOT the CommandGroup component
CommandAction, // secondary action on a command
CommandPage, // page opened by a command (placeholder + async onSearch)
SearchResult, // { command, score, matches, groupId?, parents?, matchedField? }
SearchFn, // custom search strategy signature
PaletteMode, // prefix-activated scope
CommandUsage, // frecency stat { count, lastUsed }
PaletteOptions,
PaletteLabels, // customisable UI strings (i18n)
PaletteContext,
PaletteState,
CommandStore,
KeyboardManager,
} from '@macrulez/vue-command-palette'Note: The named export
CommandGroupis the Vue component. The group-definition interface is exported asCommandGroupTypeto avoid the collision.