Skip to content

useCommandRegistry ​

Every command the palette can run. Modules register theirs at load time; the palette reads one reactive list.

Open in demo

Import ​

ts
import { useCommandRegistry } from '@shared/composables/useCommandRegistry'

Signature ​

ts
function useCommandRegistry(): {
  commands: Readonly<Ref<Command[]>>
  recentIds: Readonly<Ref<string[]>>
  register: (cmd: Command | Command[]) => void
  unregister: (id: string) => void
  execute: (id: string) => Promise<void>
}

Returns ​

MemberTypeDescription
commandsReadonly<Ref<Command[]>>Everything registered, in registration order.
recentIdsReadonly<Ref<string[]>>The last eight executed, newest first. Persisted.
register(cmd | cmd[]) => voidAdds, or replaces one with the same id.
unregister(id) => voidRemoves by id.
execute(id) => Promise<void>Records recency, then awaits the handler.

Command ​

KeyTypeDescription
idstringUnique. A second registration with the same id replaces the first.
titlestringWhat the palette lists.
group'pages' | 'actions' | 'recent' | 'settings'Which section it appears under.
iconComponentA lucide icon.
shortcutstringA display-only hint such as 'g d'. It binds nothing.
keywordsstring[]Extra words the fuzzy search should match.
featurekeyof SmartAdminConfig['features']Hide the command while that flag is off.
handler() => void | Promise<void>What running it does.

Example ​

ts
import { useCommandRegistry } from '@shared/composables/useCommandRegistry'
import { FilePlus, Users } from 'lucide-vue-next'
import { router } from './router'

const { register } = useCommandRegistry()

register([
  {
    id: 'invoices.new',
    title: 'New invoice',
    group: 'actions',
    icon: FilePlus,
    keywords: ['create', 'bill', 'draft'],
    handler: () => { void router.push('/invoices/new') },
  },
  {
    id: 'customers.list',
    title: 'Go to customers',
    group: 'pages',
    icon: Users,
    shortcut: 'g c',
    keywords: ['clients', 'accounts'],
    handler: () => { void router.push('/customers') },
  },
])

Notes ​

  • execute is the only entry point. It records recency and then runs the handler, so no caller ever touches recentIds. Calling handler() yourself skips the recency.
  • recentIds is capped at eight, deduped, and persisted under sa-recent-commands.
  • Re-registering the same id replaces it in place, keeping its position in the list. That is what makes a module safe to hot-reload.
  • feature is filtered by the palette, not at registration. Registration runs once at boot; the flag is a live setting, so a command switched off in Settings disappears on the next open rather than the next reload.
  • keywords is how "clients" finds "Go to customers". Without it the fuzzy search only sees the title.
  • commands is readonly. Add and remove through register and unregister.