Overview
The Command Palette component provides a powerful command/search interface with fuzzy search, keyboard navigation, and virtualization support. Ideal for command menus, search interfaces, and quick actions.
Basic Usage
<template>
<UCommandPalette v-model:open="isOpen" :groups="commandGroups">
<template #default>
<UButton>Open Command Palette</UButton>
</template>
</UCommandPalette>
</template>
<script setup>
const isOpen = ref(false)
const commandGroups = [
{
id: 'actions',
label: 'Actions',
items: [
{ label: 'New File', icon: 'i-lucide-file-plus', onSelect: () => console.log('New file') },
{ label: 'Open File', icon: 'i-lucide-folder-open', onSelect: () => console.log('Open file') },
{ label: 'Save', icon: 'i-lucide-save', onSelect: () => console.log('Save') }
]
},
{
id: 'navigation',
label: 'Navigation',
items: [
{ label: 'Go to Dashboard', icon: 'i-lucide-layout-dashboard' },
{ label: 'Go to Settings', icon: 'i-lucide-settings' }
]
}
]
</script>
Props
Array of command groups to display. See Group Properties below.
size
'xs' | 'sm' | 'md' | 'lg' | 'xl'
default:"'md'"
The size of the command palette.
icon
string
default:"appConfig.ui.icons.search"
The icon displayed in the input. Accepts Iconify icon names.
The icon displayed on the right side of the input.
selectedIcon
string
default:"appConfig.ui.icons.check"
The icon displayed when an item is selected.
childrenIcon
string
default:"appConfig.ui.icons.chevronRight"
The icon displayed when an item has children.
placeholder
string
default:"t('commandPalette.placeholder')"
The placeholder text for the input.
Automatically focus the input when component is mounted.
close
boolean | ButtonProps
default:"false"
Display a close button in the input. Can be configured with button props: { size: 'md', color: 'neutral', variant: 'ghost' }
closeIcon
string
default:"appConfig.ui.icons.close"
The icon displayed in the close button.
back
boolean | ButtonProps
default:"true"
Display a button to navigate back in history. Can be configured with button props.
backIcon
string
default:"appConfig.ui.icons.arrowLeft"
The icon displayed in the back button.
input
boolean | InputProps
default:"true"
Configure the input or hide it with false.
Show loading state in the input.
loadingIcon
string
default:"appConfig.ui.icons.loading"
The icon displayed when loading.
Options for fuzzy search via useFuse. Default includes:{
fuseOptions: {
ignoreLocation: true,
threshold: 0.1,
keys: ['label', 'suffix']
},
resultLimit: 12,
matchAllWhenSearchEmpty: true
}
virtualize
boolean | object
default:"false"
Enable virtualization for large lists. Can be configured with { overscan: 12, estimateSize: 32 }
Selected value(s) (v-model).
Search query (v-model:searchTerm).
Allow multiple selections.
Disable the command palette.
Key to use as value instead of the entire object.
The key used to get the label from items.
descriptionKey
string
default:"'description'"
The key used to get the description from items.
Whether to preserve group order when filtering.
Highlight items on hover.
Behavior when selecting items.
by
string | ((a: any, b: any) => boolean)
Custom comparison function for value matching.
The element or component this component should render as.
Theme customization object for component slots.
Events
update:modelValue
(value: any | any[]) => void
Emitted when the selected value changes.
Emitted when the search term changes.
Emitted when triggered via the close button.
Slots
Content displayed when no items match the search.
Footer content at the bottom of the palette.
Customize the back button.
Customize the close button.
item
{ item: CommandPaletteItem, index: number, ui: object }
Customize item rendering.
item-leading
{ item: CommandPaletteItem, index: number, ui: object }
Customize the leading section of items.
item-label
{ item: CommandPaletteItem, index: number, ui: object }
Customize the label section of items.
item-description
{ item: CommandPaletteItem, index: number, ui: object }
Customize the description section of items.
item-trailing
{ item: CommandPaletteItem, index: number, ui: object }
Customize the trailing section of items.
Group Properties
Unique identifier for the group.
Display label for the group.
Array of items in this group.
When true, items will not be filtered by fuzzy search. Useful for custom filtering.
postFilter
(searchTerm: string, items: CommandPaletteItem[]) => CommandPaletteItem[]
Custom filter function applied after fuzzy search.
Icon displayed for highlighted items in this group.
Custom slot name for items in this group.
Item Properties
The text label for the item.
Text displayed before the label.
Text displayed after the label.
Description text shown below the label.
Iconify icon name to display.
Avatar to display instead of an icon.
kbds
KbdProps['value'][] | KbdProps[]
Keyboard shortcuts to display.
Manually mark item as active.
Show loading state for the item.
Custom slot name for this item.
Placeholder to display when the item has children.
Callback fired when the item is selected.
Examples
With Keyboard Shortcuts
<template>
<UCommandPalette v-model:open="isOpen" :groups="groups">
<template #default>
<UButton>Open Commands</UButton>
</template>
</UCommandPalette>
</template>
<script setup>
const isOpen = ref(false)
const groups = [
{
id: 'file',
label: 'File',
items: [
{ label: 'New', icon: 'i-lucide-file-plus', kbds: ['meta', 'N'] },
{ label: 'Open', icon: 'i-lucide-folder-open', kbds: ['meta', 'O'] },
{ label: 'Save', icon: 'i-lucide-save', kbds: ['meta', 'S'] }
]
}
]
</script>
With Nested Navigation
<template>
<UCommandPalette :groups="groups" />
</template>
<script setup>
const groups = [
{
id: 'navigation',
label: 'Quick Navigation',
items: [
{
label: 'Settings',
icon: 'i-lucide-settings',
placeholder: 'Search settings...',
children: [
{ label: 'Profile', icon: 'i-lucide-user' },
{ label: 'Security', icon: 'i-lucide-shield' },
{ label: 'Notifications', icon: 'i-lucide-bell' }
]
},
{
label: 'Projects',
icon: 'i-lucide-folder',
placeholder: 'Search projects...',
children: [
{ label: 'Project Alpha', avatar: { text: 'A' } },
{ label: 'Project Beta', avatar: { text: 'B' } }
]
}
]
}
]
</script>
With Custom Filtering
<template>
<UCommandPalette :groups="groups" />
</template>
<script setup>
const recentItems = ref([
{ label: 'index.vue', icon: 'i-lucide-file' },
{ label: 'app.config.ts', icon: 'i-lucide-file' }
])
const groups = computed(() => [
{
id: 'recent',
label: 'Recent',
ignoreFilter: true,
items: recentItems.value
},
{
id: 'files',
label: 'All Files',
items: [
{ label: 'components/Button.vue', icon: 'i-lucide-file' },
{ label: 'pages/index.vue', icon: 'i-lucide-file' },
// ... more files
]
}
])
</script>
With Virtualization
<template>
<UCommandPalette
:groups="groups"
:virtualize="{ overscan: 10, estimateSize: 40 }"
/>
</template>
<script setup>
const groups = [
{
id: 'all',
items: Array.from({ length: 10000 }, (_, i) => ({
label: `Item ${i + 1}`,
icon: 'i-lucide-file'
}))
}
]
</script>
With Multiple Selection
<template>
<UCommandPalette
v-model="selected"
multiple
:groups="groups"
/>
</template>
<script setup>
const selected = ref([])
const groups = [
{
id: 'users',
label: 'Select Users',
items: [
{ label: 'Alice', avatar: { text: 'A' } },
{ label: 'Bob', avatar: { text: 'B' } },
{ label: 'Charlie', avatar: { text: 'C' } }
]
}
]
</script>
With Custom Empty State
<template>
<UCommandPalette :groups="groups">
<template #empty="{ searchTerm }">
<div class="p-8 text-center">
<p class="text-muted">No results for "{{ searchTerm }}"</p>
<UButton @click="handleCreateNew" size="sm" class="mt-4">
Create "{{ searchTerm }}"
</UButton>
</div>
</template>
</UCommandPalette>
</template>
<template>
<UCommandPalette :groups="groups">
<template #footer>
<div class="flex items-center justify-between p-2 border-t">
<span class="text-sm text-muted">{{ results.length }} results</span>
<div class="flex gap-2">
<UKbd>↑</UKbd>
<UKbd>↓</UKbd>
<span class="text-sm text-muted">to navigate</span>
</div>
</div>
</template>
</UCommandPalette>
</template>
Global Command Palette
<template>
<div>
<UCommandPalette
v-model:open="isOpen"
:groups="groups"
:input="{ placeholder: 'Type a command or search...' }"
close
/>
<!-- Global keyboard shortcut -->
<div @keydown.meta.k.prevent="isOpen = true">
<!-- Your app content -->
</div>
</div>
</template>
<script setup>
const isOpen = ref(false)
// Listen for Cmd/Ctrl+K globally
onMounted(() => {
const handleKeydown = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault()
isOpen.value = true
}
}
window.addEventListener('keydown', handleKeydown)
onUnmounted(() => window.removeEventListener('keydown', handleKeydown))
})
</script>
Fuzzy Search
The Command Palette uses Fuse.js for fuzzy searching. You can customize the search behavior:
<UCommandPalette
:fuse="{
fuseOptions: {
threshold: 0.3,
keys: ['label', 'description', 'suffix'],
ignoreLocation: true
},
resultLimit: 20
}"
:groups="groups"
/>