Skip to main content

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

groups
CommandPaletteGroup[]
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.
trailingIcon
string
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.
autofocus
boolean
default:"true"
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.
loading
boolean
Show loading state in the input.
loadingIcon
string
default:"appConfig.ui.icons.loading"
The icon displayed when loading.
fuse
UseFuseOptions
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 }
modelValue
any | any[]
Selected value(s) (v-model).
searchTerm
string
Search query (v-model:searchTerm).
multiple
boolean
Allow multiple selections.
disabled
boolean
Disable the command palette.
valueKey
string
Key to use as value instead of the entire object.
labelKey
string
default:"'label'"
The key used to get the label from items.
descriptionKey
string
default:"'description'"
The key used to get the description from items.
preserveGroupOrder
boolean
default:"false"
Whether to preserve group order when filtering.
highlightOnHover
boolean
default:"true"
Highlight items on hover.
selectionBehavior
'toggle' | 'replace'
Behavior when selecting items.
by
string | ((a: any, b: any) => boolean)
Custom comparison function for value matching.
as
any
default:"'div'"
The element or component this component should render as.
class
any
CSS class for styling.
ui
object
Theme customization object for component slots.

Events

update:modelValue
(value: any | any[]) => void
Emitted when the selected value changes.
update:searchTerm
(term: string) => void
Emitted when the search term changes.
update:open
(open: boolean) => void
Emitted when triggered via the close button.

Slots

empty
{ searchTerm?: string }
Content displayed when no items match the search.
Footer content at the bottom of the palette.
back
{ ui: object }
Customize the back button.
close
{ ui: object }
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

id
string
required
Unique identifier for the group.
label
string
Display label for the group.
items
CommandPaletteItem[]
Array of items in this group.
ignoreFilter
boolean
default:"false"
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.
highlightedIcon
string
Icon displayed for highlighted items in this group.
slot
string
Custom slot name for items in this group.

Item Properties

label
string
The text label for the item.
prefix
string
Text displayed before the label.
suffix
string
Text displayed after the label.
description
string
Description text shown below the label.
icon
string
Iconify icon name to display.
avatar
AvatarProps
Avatar to display instead of an icon.
chip
ChipProps
Chip/badge to display.
kbds
KbdProps['value'][] | KbdProps[]
Keyboard shortcuts to display.
active
boolean
Manually mark item as active.
loading
boolean
Show loading state for the item.
disabled
boolean
Disable the item.
slot
string
Custom slot name for this item.
placeholder
string
Placeholder to display when the item has children.
children
CommandPaletteItem[]
Nested child items.
onSelect
(e: Event) => void
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>
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"
/>

Build docs developers (and LLMs) love