CommandPalette

Fuse.jsListboxGitLab
Uma paleta de comandos com busca em texto completo baseada no Fuse.js para correspondência aproximada eficiente.

Uso

Use a diretiva v-model para controlar o valor do CommandPalette ou a prop default-value para definir o valor inicial quando você não precisa controlar o estado.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <NCommandPalette v-model="value" :groups="groups" class="flex-1 h-80" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <NCommandPalette v-model="value" :groups="groups" class="flex-1 h-80" />
</template>
Você também pode usar o evento @update:model-value para escutar o(s) item(ns) selecionado(s).

Grupos

O componente CommandPalette filtra os grupos e classifica os comandos correspondentes por relevância conforme o usuário digita. Ele oferece resultados de busca dinâmicos e instantâneos para uma descoberta de comandos eficiente. Use a prop groups como um array de objetos com as seguintes propriedades:

Você precisa fornecer um id para cada grupo, caso contrário o grupo será ignorado.

Cada grupo contém um array items de objetos que definem os comandos. Cada item pode ter as seguintes propriedades:

  • prefix?: string
  • label?: string
  • suffix?: string
  • icon?: string
  • avatar?: AvatarProps
  • chip?: ChipProps
  • kbds?: string[] | KbdProps[]
  • active?: boolean
  • loading?: boolean
  • disabled?: boolean
  • slot?: string
  • placeholder?: string
  • children?: CommandPaletteItem[]
  • onSelect?: (e: Event) => void
  • class?: any
  • ui?: { item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue, itemLeadingChipSize?: ClassNameValue, itemLeadingChip?: ClassNameValue, itemLabel?: ClassNameValue, itemLabelPrefix?: ClassNameValue, itemLabelBase?: ClassNameValue, itemLabelSuffix?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingKbds?: ClassNameValue, itemTrailingKbdsSize?: ClassNameValue, itemTrailingHighlightedIcon?: ClassNameValue, itemTrailingIcon?: ClassNameValue }

Você pode passar qualquer propriedade do componente Link, como to, target, etc.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <NCommandPalette v-model="value" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <NCommandPalette v-model="value" :groups="groups" class="flex-1" />
</template>
Cada item pode receber um array children de objetos com as seguintes propriedades para criar submenus:

Múltiplo

Use a prop multiple para permitir múltiplas seleções.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([])
</script>

<template>
  <NCommandPalette multiple v-model="value" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([])
</script>

<template>
  <NCommandPalette multiple v-model="value" :groups="groups" class="flex-1" />
</template>
Certifique-se de passar um array para a prop default-value ou para a diretiva v-model.

Placeholder

Use a prop placeholder para alterar o texto de placeholder.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette placeholder="Search an app..." :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette placeholder="Search an app..." :groups="groups" class="flex-1" />
</template>

Tamanho 4.4+

Use a prop size para alterar o tamanho do CommandPalette.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette size="xl" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette size="xl" :groups="groups" class="flex-1" />
</template>

Ícone

Use a prop icon para personalizar o Icon do input. O padrão é i-lucide-search.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette icon="i-lucide-box" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette icon="i-lucide-box" :groups="groups" class="flex-1" />
</template>
Você pode personalizar esse ícone globalmente no seu app.config.ts na chave ui.icons.search.
Você pode personalizar esse ícone globalmente no seu vite.config.ts na chave ui.icons.search.

Ícone de selecionado

Use a prop selected-icon para personalizar o Icon do item selecionado. O padrão é i-lucide-check.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy'
    }
  }
])
</script>

<template>
  <NCommandPalette multiple v-model="value" selected-icon="i-lucide-circle-check" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        avatar: {
          src: 'https://github.com/danielroe.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        avatar: {
          src: 'https://github.com/genu.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy'
    }
  }
])
</script>

<template>
  <NCommandPalette multiple v-model="value" selected-icon="i-lucide-circle-check" :groups="groups" class="flex-1" />
</template>
Você pode personalizar esse ícone globalmente no seu app.config.ts na chave ui.icons.check.
Você pode personalizar esse ícone globalmente no seu vite.config.ts na chave ui.icons.check.

Ícone à direita

Use a prop trailing-icon para personalizar o Icon à direita quando um item tem filhos. O padrão é i-lucide-chevron-right.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'actions',
    items: [
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Email',
            icon: 'i-lucide-mail'
          },
          {
            label: 'Copy',
            icon: 'i-lucide-copy'
          },
          {
            label: 'Link',
            icon: 'i-lucide-link'
          }
        ]
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette trailing-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'actions',
    items: [
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Email',
            icon: 'i-lucide-mail'
          },
          {
            label: 'Copy',
            icon: 'i-lucide-copy'
          },
          {
            label: 'Link',
            icon: 'i-lucide-link'
          }
        ]
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette trailing-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
Você pode personalizar esse ícone globalmente no seu app.config.ts na chave ui.icons.chevronRight.
Você pode personalizar esse ícone globalmente no seu vite.config.ts na chave ui.icons.chevronRight.

Carregando

Use a prop loading para exibir um ícone de carregamento no CommandPalette.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette loading :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette loading :groups="groups" class="flex-1" />
</template>

Ícone de carregamento

Use a prop loading-icon para personalizar o ícone de carregamento. O padrão é i-lucide-loader-circle.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette loading loading-icon="i-lucide-loader" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette loading loading-icon="i-lucide-loader" :groups="groups" class="flex-1" />
</template>
Você pode personalizar esse ícone globalmente no seu app.config.ts na chave ui.icons.loading.
Você pode personalizar esse ícone globalmente no seu vite.config.ts na chave ui.icons.loading.

Fechar

Use a prop close para exibir um Button para dispensar o CommandPalette.

Um evento update:open será emitido quando o botão de fechar for clicado.
<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette close :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette close :groups="groups" class="flex-1" />
</template>

Você pode passar qualquer propriedade do componente Button para personalizá-lo.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette
    :close="{
      color: 'primary',
      variant: 'outline',
      class: 'rounded-full'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette
    :close="{
      color: 'primary',
      variant: 'outline',
      class: 'rounded-full'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>

Ícone de fechar

Use a prop close-icon para personalizar o Icon do botão de fechar. O padrão é i-lucide-x.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette close close-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette close close-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
Você pode personalizar esse ícone globalmente no seu app.config.ts na chave ui.icons.close.
Você pode personalizar esse ícone globalmente no seu vite.config.ts na chave ui.icons.close.

Voltar

Use a prop back para personalizar ou ocultar o botão de voltar (com o valor false) exibido ao navegar para dentro de um submenu.

Você pode passar qualquer propriedade do componente Button para personalizá-lo.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'actions',
    items: [
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Email',
            icon: 'i-lucide-mail'
          },
          {
            label: 'Copy',
            icon: 'i-lucide-copy'
          },
          {
            label: 'Link',
            icon: 'i-lucide-link'
          }
        ]
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette
    :back="{
      color: 'primary'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'actions',
    items: [
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Email',
            icon: 'i-lucide-mail'
          },
          {
            label: 'Copy',
            icon: 'i-lucide-copy'
          },
          {
            label: 'Link',
            icon: 'i-lucide-link'
          }
        ]
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette
    :back="{
      color: 'primary'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>

Ícone de voltar

Use a prop back-icon para personalizar o Icon do botão de voltar. O padrão é i-lucide-arrow-left.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'actions',
    items: [
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Email',
            icon: 'i-lucide-mail'
          },
          {
            label: 'Copy',
            icon: 'i-lucide-copy'
          },
          {
            label: 'Link',
            icon: 'i-lucide-link'
          }
        ]
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette back-icon="i-lucide-house" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'actions',
    items: [
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Email',
            icon: 'i-lucide-mail'
          },
          {
            label: 'Copy',
            icon: 'i-lucide-copy'
          },
          {
            label: 'Link',
            icon: 'i-lucide-link'
          }
        ]
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette back-icon="i-lucide-house" :groups="groups" class="flex-1" />
</template>
Você pode personalizar esse ícone globalmente no seu app.config.ts na chave ui.icons.arrowLeft.
Você pode personalizar esse ícone globalmente no seu vite.config.ts na chave ui.icons.arrowLeft.

Desabilitado

Use a prop disabled para desabilitar o CommandPalette.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette disabled :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nitro/ui'

const groups = ref<CommandPaletteGroup[]>([
  {
    id: 'apps',
    items: [
      {
        label: 'Calendar',
        icon: 'i-lucide-calendar'
      },
      {
        label: 'Music',
        icon: 'i-lucide-music'
      },
      {
        label: 'Maps',
        icon: 'i-lucide-map'
      }
    ]
  }
])
</script>

<template>
  <NCommandPalette disabled :groups="groups" class="flex-1" />
</template>

Exemplos

Controlar o(s) item(ns) selecionado(s)

Você pode controlar o(s) item(ns) selecionado(s) usando a prop default-value ou a diretiva v-model, usando o campo onSelect em cada item ou usando o evento @update:model-value.

Use a prop value-key para selecionar um campo de um item para usar como valor em vez do objeto em si. Use a prop by para comparar objetos por um campo em vez de por referência.

Controlar o termo de busca

Use a diretiva v-model:search-term para controlar o termo de busca.

Este exemplo usa o evento @update:model-value para redefinir o termo de busca quando um item é selecionado.

Com filhos nos itens

Você pode criar menus hierárquicos usando a propriedade children nos itens. Quando um item tem filhos, ele exibe automaticamente um ícone de chevron e habilita a navegação para dentro de um submenu.

Ao navegar para dentro de um submenu:
  • The search term is reset
  • A back button appears in the input
  • You can go back to the previous group by pressing the key

Com itens buscados

Você pode buscar itens de uma API e usá-los no CommandPalette.

Nenhum dado
Este exemplo usa useLazyFetch com server: false para buscar os dados no cliente sem bloquear a renderização inicial. O estado de carregamento verifica os status pending e idle para exibir um indicador de carregamento antes e durante a busca.

Com filtro ignorado

Você pode definir o campo ignoreFilter como true em um grupo para desabilitar a busca interna e usar sua própria lógica de busca.

Nenhum dado
Este exemplo usa refDebounced para aplicar debounce nas chamadas de API. O estado de carregamento verifica os status pending e idle para exibir um indicador de carregamento antes e durante a busca.

Com itens pós-filtrados

Você pode usar o campo postFilter em um grupo para filtrar os itens depois que a busca aconteceu.

Comece a digitar para ver os itens de nível mais alto aparecerem.

Com busca fuse personalizada

Você pode usar a prop fuse para sobrescrever as opções do useFuse, cujo padrão é:

{
  fuseOptions: {
    ignoreLocation: true,
    threshold: 0.1,
    keys: ['label', 'description', 'suffix']
  },
  resultLimit: 12,
  matchAllWhenSearchEmpty: true
}
As fuseOptions são as opções do Fuse.js, o resultLimit é o número máximo de resultados a retornar e o matchAllWhenSearchEmpty é um booleano para corresponder a todos os itens quando o termo de busca está vazio.

Você pode, por exemplo, definir { fuseOptions: { includeMatches: true } } para destacar o termo de busca nos itens.

Nenhum dado

Com virtualização 4.1+

Use a prop virtualize para habilitar a virtualização em listas grandes, como um booleano ou um objeto com opções como { estimateSize: 32, overscan: 12 }.

Quando habilitado, todos os grupos são achatados em uma única lista devido a uma limitação do Reka UI.

Dentro de um Popover

Você pode usar o componente CommandPalette dentro do conteúdo de um Popover.

Dentro de um Modal

Você pode usar o componente CommandPalette dentro do conteúdo de um Modal.

Este exemplo usa useLazyFetch com immediate: false para buscar os dados apenas quando o Modal abre.

Dentro de um Drawer

Você pode usar o componente CommandPalette dentro do conteúdo de um Drawer.

Este exemplo usa useLazyFetch com immediate: false para buscar os dados apenas quando o Drawer abre.

Escutar o estado de abertura

Ao usar a prop close, você pode escutar o evento update:open quando o botão é clicado.

Isso pode ser útil ao usar o CommandPalette dentro de um Modal, por exemplo.

Com slot de rodapé

Use o slot #footer para adicionar conteúdo personalizado na parte inferior do CommandPalette, como ajuda de atalhos de teclado ou ações adicionais.

Com slot personalizado

Use a propriedade slot para personalizar um item ou grupo específico.

Você terá acesso aos seguintes slots:

  • #{{ item.slot }}
  • #{{ item.slot }}-leading
  • #{{ item.slot }}-label
  • #{{ item.slot }}-trailing
  • #{{ group.slot }}
  • #{{ group.slot }}-leading
  • #{{ group.slot }}-label
  • #{{ group.slot }}-trailing
Você também pode usar os slots #item, #item-leading, #item-label e #item-trailing para personalizar todos os itens.

API

Props

Prop Default Type
as'div'any

The element or component this component should render as.

size'md' "sm" | "md" | "xs" | "lg" | "xl"
iconappConfig.ui.icons.searchany

The icon displayed in the input. Set to false to hide the icon.

trailingIconappConfig.ui.icons.searchany

The icon displayed on the right side of the input.

selectedIconappConfig.ui.icons.checkany

The icon displayed when an item is selected.

childrenIconappConfig.ui.icons.chevronRightany

The icon displayed when an item has children.

placeholdert('commandPalette.placeholder') string

The placeholder text for the input.

autofocustrueboolean

Automatically focus the input when component is mounted.

closefalseboolean | Omit<ButtonProps, LinkPropsKeys>

Display a close button in the input (useful when inside a Modal for example). { size: 'md', color: 'neutral', variant: 'ghost' }

closeIconappConfig.ui.icons.closeany

The icon displayed in the close button.

backtrueboolean | Omit<ButtonProps, LinkPropsKeys>

Display a button to navigate back in history. { size: 'md', color: 'neutral', variant: 'link' }

backIconappConfig.ui.icons.arrowLeftany

The icon displayed in the back button.

inputtrueboolean | Omit<InputProps<AcceptableValue, ModelModifiers>, "modelValue" | "defaultValue">

Configure the input or hide it with false.

groups G[]
fuse{ fuseOptions: { ignoreLocation: true, threshold: 0.1, keys: ['label', 'description', 'suffix'] }, resultLimit: 12, matchAllWhenSearchEmpty: true } UseFuseOptions<T>

Options for useFuse.

virtualizefalseboolean | { overscan?: number ; estimateSize?: number | ((index: number) => number) | undefined; } | undefined

Enable virtualization for large lists. Note: when enabled, all groups are flattened into a single list due to a limitation of Reka UI (https://github.com/unovue/reka-ui/issues/1885).

valueKeyundefined keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

When items is an array of objects, select the field to use as the value instead of the object itself.

labelKey'label' keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

The key used to get the label from the item.

descriptionKey'description' keyof Extract<NestedItem<T>, object> & string | DotPathKeys<Extract<NestedItem<T>, object>>

The key used to get the description from the item.

preserveGroupOrderfalseboolean

Whether to preserve the order of groups as defined in the groups prop when filtering. When false, groups will appear based on item matches.

searchDelay0 number

Delay (in milliseconds) before the search term is passed to Fuse (debounced). Useful when indexing large datasets where fuzzy search becomes the bottleneck — the input stays responsive while Fuse and the result pipeline only re-run after typing settles. Set to 0 (the default) to disable.

multipleboolean

Whether multiple options can be selected or not.

disabledboolean

When true, prevents the user from interacting with listbox

modelValue null | string | number | bigint | Record<string, any> | AcceptableValue[]

The controlled value of the listbox. Can be binded with v-model.

defaultValue null | string | number | bigint | Record<string, any> | AcceptableValue[]

The value of the listbox when initially rendered. Use when you do not need to control the state of the Listbox

highlightOnHovertrueboolean

When true, hover over item will trigger highlight

selectionBehavior'toggle' "replace" | "toggle"

How multiple selection should behave in the collection.

by string | (a: AcceptableValue, b: AcceptableValue): boolean

Use this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared.

loadingboolean

When true, the loading icon will be displayed.

loadingIconappConfig.ui.icons.loadingany

The icon when the loading prop is true.

searchTerm'' string
ui { root?: SlotClass; input?: SlotClass; close?: SlotClass; back?: SlotClass; content?: SlotClass; footer?: SlotClass; viewport?: SlotClass; group?: SlotClass; empty?: SlotClass; label?: SlotClass; item?: SlotClass; itemLeadingIcon?: SlotClass; itemLeadingAvatar?: SlotClass; itemLeadingAvatarSize?: SlotClass; itemLeadingChip?: SlotClass; itemLeadingChipSize?: SlotClass; itemTrailing?: SlotClass; itemTrailingIcon?: SlotClass; itemTrailingHighlightedIcon?: SlotClass; itemTrailingKbds?: SlotClass; itemTrailingKbdsSize?: SlotClass; itemWrapper?: SlotClass; itemLabel?: SlotClass; itemLabelBase?: SlotClass; itemLabelPrefix?: SlotClass; itemLabelSuffix?: SlotClass; itemDescription?: SlotClass; }

Slots

Slot Type
empty{ searchTerm: string; }
footer{ ui: object; }
back{ ui: object; }
close{ ui: object; }
item{ item: T; index: number; ui: object; }
item-leading{ item: T; index: number; ui: object; }
item-label{ item: T; index: number; ui: object; }
item-description{ item: T; index: number; ui: object; }
item-trailing{ item: T; index: number; ui: object; }
group-label{ group: G; label: string; ui: object; }

Emits

Event Type
update:modelValue[value: T]
highlight[payload: { ref: HTMLElement; value: T; } | undefined]
entryFocus[event: CustomEvent<any>]
leave[event: Event]
update:open[value: boolean]
update:searchTerm[value: string]

Tema

app.config.ts
export default defineAppConfig({
  ui: {
    commandPalette: {
      slots: {
        root: 'flex flex-col min-h-0 min-w-0 divide-y divide-default',
        input: '',
        close: '',
        back: 'p-0',
        content: 'relative overflow-hidden flex flex-col',
        footer: 'p-1',
        viewport: 'relative scroll-py-1 overflow-y-auto flex-1 focus:outline-none',
        group: 'p-1 isolate',
        empty: 'text-center text-muted',
        label: 'font-semibold text-highlighted',
        item: 'group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75',
        itemLeadingIcon: 'shrink-0',
        itemLeadingAvatar: 'shrink-0',
        itemLeadingAvatarSize: '',
        itemLeadingChip: 'shrink-0',
        itemLeadingChipSize: '',
        itemTrailing: 'ms-auto inline-flex items-center',
        itemTrailingIcon: 'shrink-0',
        itemTrailingHighlightedIcon: 'shrink-0 text-dimmed hidden group-data-highlighted:inline-flex',
        itemTrailingKbds: 'hidden lg:inline-flex items-center shrink-0',
        itemTrailingKbdsSize: '',
        itemWrapper: 'flex-1 flex flex-col text-start min-w-0',
        itemLabel: 'truncate space-x-1 text-dimmed',
        itemLabelBase: 'text-highlighted [&>mark]:text-primary [&>mark]:bg-primary/15',
        itemLabelPrefix: 'text-default',
        itemLabelSuffix: 'text-dimmed [&>mark]:text-primary [&>mark]:bg-primary/15',
        itemDescription: 'truncate text-muted [&>mark]:text-primary [&>mark]:bg-primary/15'
      },
      variants: {
        virtualize: {
          true: {
            viewport: 'p-1 isolate'
          },
          false: {
            viewport: 'divide-y divide-default'
          }
        },
        size: {
          xs: {
            input: '[&>input]:h-10',
            empty: 'py-3 text-xs',
            label: 'p-1 text-[10px]/3 gap-1',
            item: 'p-1 text-xs gap-1',
            itemLeadingIcon: 'size-4',
            itemLeadingAvatarSize: '3xs',
            itemLeadingChip: 'size-4',
            itemLeadingChipSize: 'sm',
            itemTrailing: 'gap-1',
            itemTrailingIcon: 'size-4',
            itemTrailingHighlightedIcon: 'size-4',
            itemTrailingKbds: 'gap-0.5',
            itemTrailingKbdsSize: 'sm'
          },
          sm: {
            input: '[&>input]:h-11',
            empty: 'py-4 text-xs',
            label: 'p-1.5 text-[10px]/3 gap-1.5',
            item: 'p-1.5 text-xs gap-1.5',
            itemLeadingIcon: 'size-4',
            itemLeadingAvatarSize: '3xs',
            itemLeadingChip: 'size-4',
            itemLeadingChipSize: 'sm',
            itemTrailing: 'gap-1.5',
            itemTrailingIcon: 'size-4',
            itemTrailingHighlightedIcon: 'size-4',
            itemTrailingKbds: 'gap-0.5',
            itemTrailingKbdsSize: 'sm'
          },
          md: {
            input: '[&>input]:h-12',
            empty: 'py-6 text-sm',
            label: 'p-1.5 text-xs gap-1.5',
            item: 'p-1.5 text-sm gap-1.5',
            itemLeadingIcon: 'size-5',
            itemLeadingAvatarSize: '2xs',
            itemLeadingChip: 'size-5',
            itemLeadingChipSize: 'md',
            itemTrailing: 'gap-1.5',
            itemTrailingIcon: 'size-5',
            itemTrailingHighlightedIcon: 'size-5',
            itemTrailingKbds: 'gap-0.5',
            itemTrailingKbdsSize: 'md'
          },
          lg: {
            input: '[&>input]:h-13',
            empty: 'py-7 text-sm',
            label: 'p-2 text-xs gap-2',
            item: 'p-2 text-sm gap-2',
            itemLeadingIcon: 'size-5',
            itemLeadingAvatarSize: '2xs',
            itemLeadingChip: 'size-5',
            itemLeadingChipSize: 'md',
            itemTrailing: 'gap-2',
            itemTrailingIcon: 'size-5',
            itemTrailingHighlightedIcon: 'size-5',
            itemTrailingKbds: 'gap-0.5',
            itemTrailingKbdsSize: 'md'
          },
          xl: {
            input: '[&>input]:h-14',
            empty: 'py-8 text-base',
            label: 'p-2 text-sm gap-2',
            item: 'p-2 text-base gap-2',
            itemLeadingIcon: 'size-6',
            itemLeadingAvatarSize: 'xs',
            itemLeadingChip: 'size-6',
            itemLeadingChipSize: 'lg',
            itemTrailing: 'gap-2',
            itemTrailingIcon: 'size-6',
            itemTrailingHighlightedIcon: 'size-6',
            itemTrailingKbds: 'gap-0.5',
            itemTrailingKbdsSize: 'lg'
          }
        },
        active: {
          true: {
            item: 'text-highlighted before:bg-elevated',
            itemLeadingIcon: 'text-default'
          },
          false: {
            item: [
              'text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
              'transition-colors before:transition-colors'
            ],
            itemLeadingIcon: [
              'text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
              'transition-colors'
            ]
          }
        },
        loading: {
          true: {
            itemLeadingIcon: 'animate-spin'
          }
        }
      },
      defaultVariants: {
        size: 'md'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nitro/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        commandPalette: {
          slots: {
            root: 'flex flex-col min-h-0 min-w-0 divide-y divide-default',
            input: '',
            close: '',
            back: 'p-0',
            content: 'relative overflow-hidden flex flex-col',
            footer: 'p-1',
            viewport: 'relative scroll-py-1 overflow-y-auto flex-1 focus:outline-none',
            group: 'p-1 isolate',
            empty: 'text-center text-muted',
            label: 'font-semibold text-highlighted',
            item: 'group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75',
            itemLeadingIcon: 'shrink-0',
            itemLeadingAvatar: 'shrink-0',
            itemLeadingAvatarSize: '',
            itemLeadingChip: 'shrink-0',
            itemLeadingChipSize: '',
            itemTrailing: 'ms-auto inline-flex items-center',
            itemTrailingIcon: 'shrink-0',
            itemTrailingHighlightedIcon: 'shrink-0 text-dimmed hidden group-data-highlighted:inline-flex',
            itemTrailingKbds: 'hidden lg:inline-flex items-center shrink-0',
            itemTrailingKbdsSize: '',
            itemWrapper: 'flex-1 flex flex-col text-start min-w-0',
            itemLabel: 'truncate space-x-1 text-dimmed',
            itemLabelBase: 'text-highlighted [&>mark]:text-primary [&>mark]:bg-primary/15',
            itemLabelPrefix: 'text-default',
            itemLabelSuffix: 'text-dimmed [&>mark]:text-primary [&>mark]:bg-primary/15',
            itemDescription: 'truncate text-muted [&>mark]:text-primary [&>mark]:bg-primary/15'
          },
          variants: {
            virtualize: {
              true: {
                viewport: 'p-1 isolate'
              },
              false: {
                viewport: 'divide-y divide-default'
              }
            },
            size: {
              xs: {
                input: '[&>input]:h-10',
                empty: 'py-3 text-xs',
                label: 'p-1 text-[10px]/3 gap-1',
                item: 'p-1 text-xs gap-1',
                itemLeadingIcon: 'size-4',
                itemLeadingAvatarSize: '3xs',
                itemLeadingChip: 'size-4',
                itemLeadingChipSize: 'sm',
                itemTrailing: 'gap-1',
                itemTrailingIcon: 'size-4',
                itemTrailingHighlightedIcon: 'size-4',
                itemTrailingKbds: 'gap-0.5',
                itemTrailingKbdsSize: 'sm'
              },
              sm: {
                input: '[&>input]:h-11',
                empty: 'py-4 text-xs',
                label: 'p-1.5 text-[10px]/3 gap-1.5',
                item: 'p-1.5 text-xs gap-1.5',
                itemLeadingIcon: 'size-4',
                itemLeadingAvatarSize: '3xs',
                itemLeadingChip: 'size-4',
                itemLeadingChipSize: 'sm',
                itemTrailing: 'gap-1.5',
                itemTrailingIcon: 'size-4',
                itemTrailingHighlightedIcon: 'size-4',
                itemTrailingKbds: 'gap-0.5',
                itemTrailingKbdsSize: 'sm'
              },
              md: {
                input: '[&>input]:h-12',
                empty: 'py-6 text-sm',
                label: 'p-1.5 text-xs gap-1.5',
                item: 'p-1.5 text-sm gap-1.5',
                itemLeadingIcon: 'size-5',
                itemLeadingAvatarSize: '2xs',
                itemLeadingChip: 'size-5',
                itemLeadingChipSize: 'md',
                itemTrailing: 'gap-1.5',
                itemTrailingIcon: 'size-5',
                itemTrailingHighlightedIcon: 'size-5',
                itemTrailingKbds: 'gap-0.5',
                itemTrailingKbdsSize: 'md'
              },
              lg: {
                input: '[&>input]:h-13',
                empty: 'py-7 text-sm',
                label: 'p-2 text-xs gap-2',
                item: 'p-2 text-sm gap-2',
                itemLeadingIcon: 'size-5',
                itemLeadingAvatarSize: '2xs',
                itemLeadingChip: 'size-5',
                itemLeadingChipSize: 'md',
                itemTrailing: 'gap-2',
                itemTrailingIcon: 'size-5',
                itemTrailingHighlightedIcon: 'size-5',
                itemTrailingKbds: 'gap-0.5',
                itemTrailingKbdsSize: 'md'
              },
              xl: {
                input: '[&>input]:h-14',
                empty: 'py-8 text-base',
                label: 'p-2 text-sm gap-2',
                item: 'p-2 text-base gap-2',
                itemLeadingIcon: 'size-6',
                itemLeadingAvatarSize: 'xs',
                itemLeadingChip: 'size-6',
                itemLeadingChipSize: 'lg',
                itemTrailing: 'gap-2',
                itemTrailingIcon: 'size-6',
                itemTrailingHighlightedIcon: 'size-6',
                itemTrailingKbds: 'gap-0.5',
                itemTrailingKbdsSize: 'lg'
              }
            },
            active: {
              true: {
                item: 'text-highlighted before:bg-elevated',
                itemLeadingIcon: 'text-default'
              },
              false: {
                item: [
                  'text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
                  'transition-colors before:transition-colors'
                ],
                itemLeadingIcon: [
                  'text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
                  'transition-colors'
                ]
              }
            },
            loading: {
              true: {
                itemLeadingIcon: 'animate-spin'
              }
            }
          },
          defaultVariants: {
            size: 'md'
          }
        }
      }
    })
  ]
})

Changelog

No recent changes