useCommandPalette
Opening and closing the palette. One ref, so the navbar button, Ctrl+K and the shortcut layer cannot disagree.
vue
<script setup lang="ts">
import type { Command } from '@shared/composables/useCommandRegistry'
import CommandPalette from '@shared/components/common/CommandPalette.vue'
import { Button } from '@shared/components/ui/button'
import { useCommandPalette } from '@shared/composables/useCommandPalette'
import { useCommandRegistry } from '@shared/composables/useCommandRegistry'
import { FilePlus, LayoutDashboard, Users } from 'lucide-vue-next'
import { onMounted, onUnmounted, ref } from 'vue'
const ran = ref('')
const DEMO: Command[] = [
{ id: 'docs-pal-dashboard', title: 'Go to dashboard', group: 'pages', icon: LayoutDashboard, shortcut: 'g d', handler: () => { ran.value = 'Go to dashboard' } },
{ id: 'docs-pal-customers', title: 'Go to customers', group: 'pages', icon: Users, keywords: ['clients', 'accounts'], handler: () => { ran.value = 'Go to customers' } },
{ id: 'docs-pal-invoice', title: 'New invoice', group: 'actions', icon: FilePlus, handler: () => { ran.value = 'New invoice' } },
]
const { open, show, hide, toggle } = useCommandPalette()
const { register, unregister } = useCommandRegistry()
onMounted(() => register(DEMO))
onUnmounted(() => {
DEMO.forEach(c => unregister(c.id))
hide()
})
</script>
<template>
<div class="flex flex-col gap-4">
<div class="flex flex-wrap items-center gap-2">
<Button size="sm" @click="show()">
Open
</Button>
<Button size="sm" variant="outline" @click="toggle()">
Toggle
</Button>
<Button size="sm" variant="outline" :disabled="!open" @click="hide()">
Close
</Button>
<span class="sa-text-sm text-muted-foreground">open: {{ open }}</span>
</div>
<CommandPalette />
<p class="rounded-lg border border-border p-3 sa-text-sm">
{{ ran ? `Ran: ${ran}` : 'Open it, type to filter, press Enter.' }}
</p>
</div>
</template>Import
ts
import { useCommandPalette } from '@shared/composables/useCommandPalette'Signature
ts
function useCommandPalette(): {
open: Ref<boolean>
show: () => void
hide: () => void
toggle: () => void
}Returns
| Member | Type | Description |
|---|---|---|
open | Ref<boolean> | Writable, so it can be bound with v-model. |
show | () => void | Opens it. |
hide | () => void | Closes it. |
toggle | () => void | Flips it. |
Example
vue
<script setup lang="ts">
import CommandPalette from '@shared/components/common/CommandPalette.vue'
import { useCommandPalette } from '@shared/composables/useCommandPalette'
const { show } = useCommandPalette()
</script>
<template>
<div>
<button type="button" @click="show()">
Search
<kbd>Ctrl K</kbd>
</button>
<CommandPalette />
</div>
</template>Notes
- It is one module-scope ref. Three things open the palette — the navbar trigger, the
Ctrl+Klistener and the command that opens it — and they all write the same state, so it cannot end up half-open. - The state only says whether the dialog is showing. What it lists comes from
useCommandRegistry. Ctrl+Kchecks thecommandPalettefeature flag inside its handler, so switching it off in Settings takes effect immediately. This composable does not check the flag; if you build your own trigger, check it yourself.- Mount
CommandPaletteonce, in your app shell. The template already does.
Related
useCommandRegistry— what the palette shows.- Command palette — the component.
useShortcuts— the key bindings around it.