---
title: CommandPalette
description: Add a customizable command palette to your app.
links:
  - label: GitHub
    icon: i-simple-icons-github
    to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/CommandPalette.vue
  - label: 'Combobox'
    icon: i-simple-icons-headlessui
    to: 'https://headlessui.com/vue/combobox'
---

## Usage

Use a `v-model` to display a searchable and selectable list of commands.

::component-example
---
padding: false
---

#default
:command-palette-example-basic{class="h-[257px]"}

#code
```vue
<script setup>
const people = [
  { id: 1, label: 'Wade Cooper' },
  { id: 2, label: 'Arlene Mccoy' },
  { id: 3, label: 'Devon Webb' },
  { id: 4, label: 'Tom Cook' },
  { id: 5, label: 'Tanya Fox' },
  { id: 6, label: 'Hellen Schmidt' },
  { id: 7, label: 'Caroline Schultz' },
  { id: 8, label: 'Mason Heaney' },
  { id: 9, label: 'Claudie Smitham' },
  { id: 10, label: 'Emil Schaefer' }
]

const selected = ref([people[3]])
</script>

<template>
  <UCommandPalette
    v-model="selected"
    multiple
    nullable
    :groups="[{ key: 'people', commands: people }]"
    :fuse="{ resultLimit: 6, fuseOptions: { threshold: 0.1 } }"
  />
</template>
```
::

You can put a `CommandPalette` anywhere you want but it's most commonly used inside of a modal.

::component-example
#default
:command-palette-example-modal

#code
```vue
<script setup>
const isOpen = ref(false)

const people = [
  { id: 1, label: 'Wade Cooper' },
  { id: 2, label: 'Arlene Mccoy' },
  { id: 3, label: 'Devon Webb' },
  { id: 4, label: 'Tom Cook' },
  { id: 5, label: 'Tanya Fox' },
  { id: 6, label: 'Hellen Schmidt' },
  { id: 7, label: 'Caroline Schultz' },
  { id: 8, label: 'Mason Heaney' },
  { id: 9, label: 'Claudie Smitham' },
  { id: 10, label: 'Emil Schaefer' }
]

const selected = ref([])
</script>

<template>
  <div>
    <UButton label="Open" @click="isOpen = true" />

    <UModal v-model="isOpen">
      <UCommandPalette
        v-model="selected"
        multiple
        nullable
        :groups="[{ key: 'people', commands: people }]"
      />
    </UModal>
  </div>
</template>
```
::

You can pass multiple groups of commands to the component. Each group will be separated by a divider and will display a label.

Without a `v-model`, you can also listen on `@update:model-value` to navigate to a link or do something else when a command is clicked.

::component-example
---
padding: false
---

#default
:command-palette-example-groups{class="h-[274px]"}

#code
```vue
<script setup>
const router = useRouter()
const toast = useToast()

const commandPaletteRef = ref()

const users = [
  { id: 'benjamincanac', label: 'benjamincanac', href: 'https://github.com/benjamincanac', target: '_blank', avatar: { src: 'https://avatars.githubusercontent.com/u/739984?v=4' } },
  { id: 'Atinux', label: 'Atinux', href: 'https://github.com/Atinux', target: '_blank', avatar: { src: 'https://avatars.githubusercontent.com/u/904724?v=4' } },
  { id: 'smarroufin', label: 'smarroufin', href: 'https://github.com/smarroufin', target: '_blank', avatar: { src: 'https://avatars.githubusercontent.com/u/7547335?v=4' } }
]

const actions = [
  { id: 'new-file', label: 'Add new file', icon: 'i-heroicons-document-plus', click: () => toast.add({ title: 'New file added!' }), shortcuts: ['⌘', 'N'] },
  { id: 'new-folder', label: 'Add new folder', icon: 'i-heroicons-folder-plus', click: () => toast.add({ title: 'New folder added!' }), shortcuts: ['⌘', 'F'] },
  { id: 'hashtag', label: 'Add hashtag', icon: 'i-heroicons-hashtag', click: () => toast.add({ title: 'Hashtag added!' }), shortcuts: ['⌘', 'H'] },
  { id: 'label', label: 'Add label', icon: 'i-heroicons-tag', click: () => toast.add({ title: 'Label added!' }), shortcuts: ['⌘', 'L'] }
]

const groups = computed(() =>
  [commandPaletteRef.value?.query ? {
    key: 'users',
    commands: users
  } : {
    key: 'recent',
    label: 'Recent searches',
    commands: users.slice(0, 1)
  }, {
    key: 'actions',
    commands: actions
  }].filter(Boolean))

function onSelect (option) {
  if (option.click) {
    option.click()
  } else if (option.to) {
    router.push(option.to)
  } else if (option.href) {
    window.open(option.href, '_blank')
  }
}
</script>

<template>
  <UCommandPalette ref="commandPaletteRef" :groups="groups" @update:model-value="onSelect" />
</template>
```
::

### Icon

Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.

Use the `selected-icon` prop to set a different icon or change it globally in `ui.commandPalette.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.

::component-card
---
padding: false
baseProps:
  emptyState: null
props:
  icon: 'i-heroicons-command-line'
excludedProps:
  - icon
---
::

### Loading

Use the `loading` prop to show a loading icon.

Use the `loading-icon` prop to set a different icon or change it globally in `ui.commandPalette.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.

::component-card
---
padding: false
baseProps:
  emptyState: null
props:
  loading: true
excludedProps:
  - icon
---
::

### Placeholder

Use the `placeholder` prop to change the input placeholder

::component-card
---
padding: false
baseProps:
  emptyState: null
props:
  placeholder: 'Type a command...'
excludedProps:
  - icon
---
::

### Close

Use the `close-button` prop to display a close button on the right side of the input.

You can pass all the props of the [Button](/elements/button) component to customize it through the `close-button` prop or globally through `ui.commandPalette.default.closeButton`.

::component-card
---
padding: false
baseProps:
  emptyState: null
props:
  closeButton:
    icon: 'i-heroicons-x-mark-20-solid'
    color: 'gray'
    variant: 'link'
    padded: false
excludedProps:
  - closeButton
---
::

### Empty

An empty state will be displayed when there are no results.

Use the `empty-state` prop to customize the `icon` and `label` or change them globally in `ui.commandPalette.default.emptyState`.

You can also set it to `null` to hide the empty state.

::component-card
---
padding: false
baseProps:
  placeholder: 'Type something to see the empty label change'
props:
  emptyState:
    icon: 'i-heroicons-magnifying-glass-20-solid'
    label: "We couldn't find any items."
    queryLabel: "We couldn't find any items with that term. Please try again."
excludedProps:
  - emptyState
---
::

## Full-text search

The CommandPalette component takes care of the full-text search for you with [Fuse.js](https://fusejs.io). You can pass all the options of Fuse.js through the `fuse` prop.

When searching for a command, the component will look for a `label` property on the command by default. You can customize this behavior by overriding the `command-attribute` prop. This will also affect the display of the command.

You can also highlight the matches in the command by setting the `fuse.fuseOptions.includeMatches` to `true`. The CommandPalette component automatically takes care of the highlighting for you.

```vue
<template>
  <UCommandPalette
    command-attribute="title"
    :fuse="{
      fuseOptions: {
        ignoreLocation: true,
        includeMatches: true,
        threshold: 0,
        keys: ['title', 'description', 'children.children.value', 'children.children.children.value']
      },
      resultLimit: 10
    }"
  />
</template>
```

::callout{icon="i-heroicons-light-bulb"}
Try it yourself in this documentation's search by pressing :kbd{value="meta"} :kbd{value="K" class="ml-1"}.
::

## Async search

You can also pass an `async` function to the `search` property of a group to perform an async search. The function will receive the query as its first argument and should return an array of commands.

::component-example
---
padding: false
---

#default
:command-palette-example-async{class="h-[274px]"}
#code
```vue
<script setup>
const groups = computed(() => {
  return [{
    key: 'users',
    label: q => q && `Users matching “${q}”...`,
    search: async (q) => {
      if (!q) {
        return []
      }

      const users = await $fetch(`https://jsonplaceholder.typicode.com/users`, { params: { q } })

      return users.map(user => ({ id: user.id, label: user.name, suffix: user.email }))
    }
  }].filter(Boolean)
})
</script>

<template>
  <UCommandPalette :groups="groups" />
</template>
```
::

::callout{icon="i-heroicons-light-bulb"}
The `loading` state will automatically be enabled when a `search` function is loading. You can disable this behavior by setting the `loading-icon` prop to `null` or globally in `ui.commandPalette.default.loadingIcon`.
::

## Slots

### `<group>-icon`

Use the `#<group>-icon` slot to override the left command content which display by default the `icon`, `avatar` and `chip`.

### `<group>-command`

Use the `#<group>-command` slot to override the command content which display by default the `prefix`, `suffix` and `label` (customizable through the `command-attribute` prop).

### `<group>-active`

Use the `#<group>-active` slot to override the right command content (when hovered) which display by default the `active` field of the group if provided.

### `<group>-inactive`

Use the `#<group>-inactive` slot to override the right command content (when not hovered) which display by default the `inactive` field of the group if provided or the `shortcuts` of the command.

::callout{icon="i-heroicons-light-bulb"}
The 4 slots above will have access to the `group`, `command`, `active` and `selected` properties in the slot scope.
::

### `empty-state`

Use the `#empty-state` slot to customize the empty state.

::component-example{class="grid"}
---
padding: false
overflowClass: 'overflow-x-auto'
---

#default
:command-palette-example-empty-slot{class="flex-1"}

#code
```vue
<script setup>
const groups = [...]
</script>

<template>
  <UCommandPalette :groups="groups">
    <template #empty-state>
      <div class="flex flex-col items-center justify-center py-6 gap-3">
        <span class="italic text-sm">Nothing here!</span>
        <UButton label="Add item" />
      </div>
    </template>
  </UCommandPalette>
</template>
```
::

## Props

:component-props

## Preset

:component-preset
