CommandPalette 명령팔레트

효율적인 퍼지 매칭을 위해 Fuse.js로 구동되는 전체 텍스트 검색이 포함된 명령 팔레트입니다.

Usage

v-model 지시어를 사용하여 CommandPalette 값을 제어하거나 default-value prop 상태를 제어할 필요가 없을 때 초기값을 설정합니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <UCommandPalette v-model="value" :groups="groups" class="flex-1 h-80" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <UCommandPalette v-model="value" :groups="groups" class="flex-1 h-80" />
</template>
@update:model-value 이벤트를 사용하여 선택한 항목을 청취할 수도 있습니다.

Groups 그룹

CommandPalette 구성 요소는 사용자 입력에 따라 일치하는 명령을 그룹화하고 순위를 지정합니다. 효율적인 명령 검색을 위해 동적인 즉각적인 검색 결과를 제공합니다. groups prop을 객체 배열로 사용하여 다음 속성을 사용합니다.

각 그룹에 대해 id를 제공해야 합니다. 그렇지 않으면 그룹이 무시됩니다.

각 그룹에는 명령을 정의하는 items 객체 배열이 포함되어 있습니다. 각 항목에는 다음 등록 정보가 있을 수 있습니다.

  • prefix?: string (- prefix?: string)
  • label?: string
  • suffix?: string
  • icon?: string
  • avatar?: AvatarProps
  • chip?: ChipProps
  • kbds?: string[] | KbdProps[]
  • active?: boolean
  • loading?: boolean
  • disabled?: boolean (- disabled?: boolean)
  • slot?: string
  • placeholder?: string
  • children?: CommandPaletteItem[] (- children?: CommandPaletteItem[])
  • onSelect?: (e: Event) => void - {lang="ts-type"} (- onSelect?: (e: Event) => void) / - onSelect?: (e: Event) => void
  • class?: any (- class?: any) / - class?: any / - 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 } (- 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 })

Link 구성 요소에서 to, target 등의 속성을 전달할 수 있습니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <UCommandPalette v-model="value" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref({})
</script>

<template>
  <UCommandPalette v-model="value" :groups="groups" class="flex-1" />
</template>
각 항목은 다음과 같은 속성을 가진 객체의 children 배열을 사용하여 하위 메뉴를 작성할 수 있습니다.

Multiple 다중

multiple prop을 사용하여 여러 선택을 허용합니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([])
</script>

<template>
  <UCommandPalette multiple v-model="value" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([])
</script>

<template>
  <UCommandPalette multiple v-model="value" :groups="groups" class="flex-1" />
</template>
배열을 default-value prop 또는 v-model 디렉티브로 전달해야 합니다.

자리 표시자

placeholder prop을 사용하여 자리 표시자 텍스트를 변경합니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette placeholder="Search an app..." :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette placeholder="Search an app..." :groups="groups" class="flex-1" />
</template>

Size : badge{label="4.4+" class="align-text-top"}

size prop을 사용하여 CommandPalette의 크기를 변경합니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette size="xl" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette size="xl" :groups="groups" class="flex-1" />
</template>

Icon

icon 소품을 사용하여 입력 Icon를 사용자 정의합니다. 기본값은 i-lucide-search입니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette icon="i-lucide-box" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette icon="i-lucide-box" :groups="groups" class="flex-1" />
</template>
ui.icons.search 키 아래의 app.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.
ui.icons.search 키 아래의 vite.config.ts에서 이 아이콘을 전역적으로 사용자 지정할 수 있습니다.

선택한 아이콘

selected-icon 소품을 사용하여 선택한 항목 Icon를 사용자 정의합니다. 기본값은 i-lucide-check입니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy'
    }
  }
])
</script>

<template>
  <UCommandPalette 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 '@nuxt/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: 'Hugo Richard',
        suffix: 'HugoRCD',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy'
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy'
        }
      }
    ]
  }
])
const value = ref([
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy'
    }
  }
])
</script>

<template>
  <UCommandPalette multiple v-model="value" selected-icon="i-lucide-circle-check" :groups="groups" class="flex-1" />
</template>
ui.icons.check 키 아래의 app.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.
ui.icons.check 키 아래의 vite.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.

트레일 아이콘

항목에 자식이 있을 때 trailing-icon 소품을 사용하여 후행 Icon를 사용자 정의합니다. 기본값은 i-lucide-chevron-right로 설정됩니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette trailing-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette trailing-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
ui.icons.chevronRight 키 아래의 app.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.
ui.icons.chevronRight 키 아래의 vite.config.ts 내에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.

loading 중

loading prop를 사용하여 CommandPalette에 로드 아이콘을 표시합니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette loading :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette loading :groups="groups" class="flex-1" />
</template>

loading 아이콘

loading-icon 소품을 사용하여 로드 아이콘을 사용자 정의합니다. 기본값은 i-lucide-loader-circle입니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette loading loading-icon="i-lucide-loader" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette loading loading-icon="i-lucide-loader" :groups="groups" class="flex-1" />
</template>
ui.icons.loading 키 아래의 app.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.
ui.icons.loading 키 아래의 vite.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.

Close (### 닫기)

close prop를 사용하여 Button를 표시하여 CommandPalette를 해제합니다.

닫기 버튼을 클릭하면 update:open 이벤트가 발생합니다.
<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette close :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette close :groups="groups" class="flex-1" />
</template>

Button 구성 요소의 모든 속성을 전달하여 사용자 정의할 수 있습니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette
    :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 '@nuxt/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>
  <UCommandPalette
    :close="{
      color: 'primary',
      variant: 'outline',
      class: 'rounded-full'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>

Close 아이콘

close-icon 소품을 사용하여 닫기 단추 Icon를 사용자 정의합니다. 기본값은 i-lucide-x입니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette 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 '@nuxt/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>
  <UCommandPalette close close-icon="i-lucide-arrow-right" :groups="groups" class="flex-1" />
</template>
ui.icons.close 키 아래의 app.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.
ui.icons.close 키 아래의 vite.config.ts에서 이 아이콘을 전역적으로 사용자 지정할 수 있습니다.

뒤로

back 소품을 사용하여 하위 메뉴로 이동할 때 표시되는 뒤로 버튼(false 값)을 사용자 정의하거나 숨깁니다.

Button 구성 요소의 모든 속성을 전달하여 사용자 정의할 수 있습니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette
    :back="{
      color: 'primary'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette
    :back="{
      color: 'primary'
    }"
    :groups="groups"
    class="flex-1"
  />
</template>

Back 아이콘

back-icon 소품을 사용하여 뒤로 단추 Icon를 사용자 정의합니다. 기본값은 i-lucide-arrow-left입니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette back-icon="i-lucide-house" :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette back-icon="i-lucide-house" :groups="groups" class="flex-1" />
</template>
ui.icons.arrowLeft 키 아래의 app.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.
ui.icons.arrowLeft 키 아래의 vite.config.ts에서 이 아이콘을 전역적으로 사용자 정의할 수 있습니다.

Disabled 사용 안 함

disabled prop를 사용하여 CommandPalette를 비활성화합니다.

<script setup lang="ts">
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette disabled :groups="groups" class="flex-1" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteGroup } from '@nuxt/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>
  <UCommandPalette disabled :groups="groups" class="flex-1" />
</template>

examples 예제

Control 선택된 항목

default-value prop 또는 v-model 지시문을 사용하거나, 각 항목에 onSelect 필드를 사용하거나, @update:model-value 이벤트를 사용하여 선택된 항목을 제어할 수 있습니다.

<script setup lang="ts">
const toast = useToast()

const groups = ref([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        to: 'https://github.com/benjamincanac',
        target: '_blank',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        to: 'https://github.com/HugoRCD',
        target: '_blank',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        to: 'https://github.com/atinux',
        target: '_blank',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        to: 'https://github.com/romhml',
        target: '_blank',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        to: 'https://github.com/sandros94',
        target: '_blank',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        to: 'https://github.com/J-Michalek',
        target: '_blank',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        to: 'https://github.com/hywax',
        target: '_blank',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        to: 'https://github.com/maximepvrt',
        target: '_blank',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy' as const
        }
      }
    ]
  },
  {
    id: 'actions',
    items: [
      {
        label: 'Add new file',
        suffix: 'Create a new file in the current directory or workspace.',
        icon: 'i-lucide-file-plus',
        kbds: [
          'meta',
          'N'
        ],
        onSelect() {
          toast.add({ title: 'Add new file' })
        }
      },
      {
        label: 'Add new folder',
        suffix: 'Create a new folder in the current directory or workspace.',
        icon: 'i-lucide-folder-plus',
        kbds: [
          'meta',
          'F'
        ],
        onSelect() {
          toast.add({ title: 'Add new folder' })
        }
      },
      {
        label: 'Add hashtag',
        suffix: 'Add a hashtag to the current item.',
        icon: 'i-lucide-hash',
        kbds: [
          'meta',
          'H'
        ],
        onSelect() {
          toast.add({ title: 'Add hashtag' })
        }
      },
      {
        label: 'Add label',
        suffix: 'Add a label to the current item.',
        icon: 'i-lucide-tag',
        kbds: [
          'meta',
          'L'
        ],
        onSelect() {
          toast.add({ title: 'Add label' })
        }
      }
    ]
  }
])

function onSelect(item: any) {
  console.log(item)
}
</script>

<template>
  <UCommandPalette
    :groups="groups"
    class="flex-1 h-80"
    @update:model-value="onSelect"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const toast = useToast()

const groups = ref([
  {
    id: 'users',
    label: 'Users',
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        to: 'https://github.com/benjamincanac',
        target: '_blank',
        avatar: {
          src: 'https://github.com/benjamincanac.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        to: 'https://github.com/HugoRCD',
        target: '_blank',
        avatar: {
          src: 'https://github.com/HugoRCD.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        to: 'https://github.com/atinux',
        target: '_blank',
        avatar: {
          src: 'https://github.com/atinux.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        to: 'https://github.com/romhml',
        target: '_blank',
        avatar: {
          src: 'https://github.com/romhml.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        to: 'https://github.com/sandros94',
        target: '_blank',
        avatar: {
          src: 'https://github.com/sandros94.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        to: 'https://github.com/J-Michalek',
        target: '_blank',
        avatar: {
          src: 'https://github.com/J-Michalek.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Alex',
        suffix: 'hywax',
        to: 'https://github.com/hywax',
        target: '_blank',
        avatar: {
          src: 'https://github.com/hywax.png',
          loading: 'lazy' as const
        }
      },
      {
        label: 'Maxime Pauvert',
        suffix: 'maximepvrt',
        to: 'https://github.com/maximepvrt',
        target: '_blank',
        avatar: {
          src: 'https://github.com/maximepvrt.png',
          loading: 'lazy' as const
        }
      }
    ]
  },
  {
    id: 'actions',
    items: [
      {
        label: 'Add new file',
        suffix: 'Create a new file in the current directory or workspace.',
        icon: 'i-lucide-file-plus',
        kbds: [
          'meta',
          'N'
        ],
        onSelect() {
          toast.add({ title: 'Add new file' })
        }
      },
      {
        label: 'Add new folder',
        suffix: 'Create a new folder in the current directory or workspace.',
        icon: 'i-lucide-folder-plus',
        kbds: [
          'meta',
          'F'
        ],
        onSelect() {
          toast.add({ title: 'Add new folder' })
        }
      },
      {
        label: 'Add hashtag',
        suffix: 'Add a hashtag to the current item.',
        icon: 'i-lucide-hash',
        kbds: [
          'meta',
          'H'
        ],
        onSelect() {
          toast.add({ title: 'Add hashtag' })
        }
      },
      {
        label: 'Add label',
        suffix: 'Add a label to the current item.',
        icon: 'i-lucide-tag',
        kbds: [
          'meta',
          'L'
        ],
        onSelect() {
          toast.add({ title: 'Add label' })
        }
      }
    ]
  }
])

function onSelect(item: any) {
  console.log(item)
}
</script>

<template>
  <UCommandPalette
    :groups="groups"
    class="flex-1 h-80"
    @update:model-value="onSelect"
  />
</template>
value-key prop을 사용하여 객체 자체가 아닌 값으로 사용할 항목의 필드를 선택합니다. by prop을 사용하여 참조가 아닌 필드로 객체를 비교합니다.

Control 검색 용어

v-model:search-term 지시문을 사용하여 검색 용어를 제어합니다.

<script setup lang="ts">
const users = [
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    to: 'https://github.com/benjamincanac',
    target: '_blank',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Hugo Richard',
    suffix: 'HugoRCD',
    to: 'https://github.com/HugoRCD',
    target: '_blank',
    avatar: {
      src: 'https://github.com/HugoRCD.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sébastien Chopin',
    suffix: 'atinux',
    to: 'https://github.com/atinux',
    target: '_blank',
    avatar: {
      src: 'https://github.com/atinux.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Romain Hamel',
    suffix: 'romhml',
    to: 'https://github.com/romhml',
    target: '_blank',
    avatar: {
      src: 'https://github.com/romhml.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sandro Circi',
    suffix: 'sandros94',
    to: 'https://github.com/sandros94',
    target: '_blank',
    avatar: {
      src: 'https://github.com/sandros94.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Jakub Michálek',
    suffix: 'J-Michalek',
    to: 'https://github.com/J-Michalek',
    target: '_blank',
    avatar: {
      src: 'https://github.com/J-Michalek.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Alex',
    suffix: 'hywax',
    to: 'https://github.com/hywax',
    target: '_blank',
    avatar: {
      src: 'https://github.com/hywax.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Maxime Pauvert',
    suffix: 'maximepvrt',
    to: 'https://github.com/maximepvrt',
    target: '_blank',
    avatar: {
      src: 'https://github.com/maximepvrt.png',
      loading: 'lazy' as const
    }
  }
]

const searchTerm = ref('B')

function onSelect() {
  searchTerm.value = ''
}
</script>

<template>
  <UCommandPalette
    v-model:search-term="searchTerm"
    :groups="[{ id: 'users', items: users }]"
    class="flex-1"
    @update:model-value="onSelect"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const users = [
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    to: 'https://github.com/benjamincanac',
    target: '_blank',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Hugo Richard',
    suffix: 'HugoRCD',
    to: 'https://github.com/HugoRCD',
    target: '_blank',
    avatar: {
      src: 'https://github.com/HugoRCD.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sébastien Chopin',
    suffix: 'atinux',
    to: 'https://github.com/atinux',
    target: '_blank',
    avatar: {
      src: 'https://github.com/atinux.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Romain Hamel',
    suffix: 'romhml',
    to: 'https://github.com/romhml',
    target: '_blank',
    avatar: {
      src: 'https://github.com/romhml.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sandro Circi',
    suffix: 'sandros94',
    to: 'https://github.com/sandros94',
    target: '_blank',
    avatar: {
      src: 'https://github.com/sandros94.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Jakub Michálek',
    suffix: 'J-Michalek',
    to: 'https://github.com/J-Michalek',
    target: '_blank',
    avatar: {
      src: 'https://github.com/J-Michalek.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Alex',
    suffix: 'hywax',
    to: 'https://github.com/hywax',
    target: '_blank',
    avatar: {
      src: 'https://github.com/hywax.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Maxime Pauvert',
    suffix: 'maximepvrt',
    to: 'https://github.com/maximepvrt',
    target: '_blank',
    avatar: {
      src: 'https://github.com/maximepvrt.png',
      loading: 'lazy' as const
    }
  }
]

const searchTerm = ref('B')

function onSelect() {
  searchTerm.value = ''
}
</script>

<template>
  <UCommandPalette
    v-model:search-term="searchTerm"
    :groups="[{ id: 'users', items: users }]"
    class="flex-1"
    @update:model-value="onSelect"
  />
</template>
이 예제에서는 @update:model-value 이벤트를 사용하여 항목을 선택할 때 검색 용어를 재설정합니다.

항목에 자식 포함

항목에서 children 등록 정보를 사용하여 계층 메뉴를 생성할 수 있습니다. 항목에 1차 하위 구성 요소가 있으면 자동으로 갈매기 모양 아이콘이 표시되고 하위 메뉴로 이동할 수 있습니다.

<script setup lang="ts">
const toast = useToast()

const groups = [
  {
    id: 'actions',
    label: 'Actions',
    items: [
      {
        label: 'Create new',
        icon: 'i-lucide-plus',
        children: [
          {
            label: 'New file',
            icon: 'i-lucide-file-plus',
            suffix: 'Create a new file in the current directory',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'New file created!' })
            },
            kbds: ['meta', 'N']
          },
          {
            label: 'New folder',
            icon: 'i-lucide-folder-plus',
            suffix: 'Create a new folder in the current directory',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'New folder created!' })
            },
            kbds: ['meta', 'F']
          },
          {
            label: 'New project',
            icon: 'i-lucide-folder-git',
            suffix: 'Create a new project from a template',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'New project created!' })
            },
            kbds: ['meta', 'P']
          }
        ]
      },
      {
        label: 'Share',
        icon: 'i-lucide-share',
        children: [
          {
            label: 'Copy link',
            icon: 'i-lucide-link',
            suffix: 'Copy a link to the current item',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'Link copied to clipboard!' })
            },
            kbds: ['meta', 'L']
          },
          {
            label: 'Share via email',
            icon: 'i-lucide-mail',
            suffix: 'Share the current item via email',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'Share via email dialog opened!' })
            }
          },
          {
            label: 'Share on social',
            icon: 'i-lucide-share-2',
            suffix: 'Share the current item on social media',
            children: [
              {
                label: 'Twitter',
                icon: 'i-simple-icons-twitter',
                onSelect(e: Event) {
                  e.preventDefault()
                  toast.add({ title: 'Shared on Twitter!' })
                }
              },
              {
                label: 'LinkedIn',
                icon: 'i-simple-icons-linkedin',
                onSelect(e: Event) {
                  e.preventDefault()
                  toast.add({ title: 'Shared on LinkedIn!' })
                }
              },
              {
                label: 'Facebook',
                icon: 'i-simple-icons-facebook',
                onSelect(e: Event) {
                  e.preventDefault()
                  toast.add({ title: 'Shared on Facebook!' })
                }
              }
            ]
          }
        ]
      },
      {
        label: 'Settings',
        icon: 'i-lucide-settings',
        children: [
          {
            label: 'General',
            icon: 'i-lucide-sliders',
            suffix: 'Configure general settings',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'General settings opened!' })
            }
          },
          {
            label: 'Appearance',
            icon: 'i-lucide-palette',
            suffix: 'Customize the appearance',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'Appearance settings opened!' })
            }
          },
          {
            label: 'Security',
            icon: 'i-lucide-shield',
            suffix: 'Manage security settings',
            onSelect(e: Event) {
              e.preventDefault()
              toast.add({ title: 'Security settings opened!' })
            }
          }
        ]
      }
    ]
  }
]
</script>

<template>
  <UCommandPalette :groups="groups" class="flex-1" />
</template>
하위 메뉴로 이동하는 경우:
  • 검색 용어가 재설정됨
  • A 뒤로 버튼이 입력에 나타납니다.
  • ⌫ 키를 눌러 이전 그룹으로 돌아갈 수 있습니다

가져온 항목 포함

API에서 항목을 가져와서 CommandPalette에서 사용할 수 있습니다.

No data
<script setup lang="ts">
const searchTerm = ref('')

const { data: users, status } = useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'command-palette-users',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  server: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || []
}])
</script>

<template>
  <UCommandPalette
    v-model:search-term="searchTerm"
    :loading="status === 'pending' || status === 'idle'"
    :groups="groups"
    class="flex-1 h-80"
  />
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'

const searchTerm = ref('')

const { data: users, status } = useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'command-palette-users',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  server: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || []
}])
</script>

<template>
  <UCommandPalette
    v-model:search-term="searchTerm"
    :loading="status === 'pending' || status === 'idle'"
    :groups="groups"
    class="flex-1 h-80"
  />
</template>
이 예에서는 useLazyFetch와 server: false를 사용하여 초기 렌더링을 차단하지 않고 클라이언트에서 데이터를 검색합니다. 로드 상태에서는 pending 및 idle 상태를 모두 확인하여 가져오기 전과 도중에 로드 표시기를 표시합니다.

Ignore 필터 사용

그룹에서 ignoreFilter 필드를 true로 설정하여 내부 검색을 비활성화하고 사용자 고유의 검색 논리를 사용할 수 있습니다.

No data
<script setup lang="ts">
import { refDebounced } from '@vueuse/core'

const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200)

const { data: users, status } = useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'command-palette-users-search',
  params: { q: searchTermDebounced },
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  server: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || [],
  ignoreFilter: true
}])
</script>

<template>
  <UCommandPalette
    v-model:search-term="searchTerm"
    :loading="status === 'pending' || status === 'idle'"
    :groups="groups"
    class="flex-1 h-80"
  />
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { refDebounced } from '@vueuse/core'

const searchTerm = ref('')
const searchTermDebounced = refDebounced(searchTerm, 200)

const { data: users, status } = useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'command-palette-users-search',
  params: { q: searchTermDebounced },
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  server: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || [],
  ignoreFilter: true
}])
</script>

<template>
  <UCommandPalette
    v-model:search-term="searchTerm"
    :loading="status === 'pending' || status === 'idle'"
    :groups="groups"
    class="flex-1 h-80"
  />
</template>
이 예에서는 refDebounced를 사용하여 API 호출을 디버깅합니다. 로드 상태는 pending 및 idle 상태를 모두 확인하여 검색 전과 도중에 로드 표시기를 표시합니다.

Post-filtered 항목 포함

검색이 수행된 후 그룹의 postFilter 필드를 사용하여 항목을 필터링할 수 있습니다.

<script setup lang="ts">
const items = [
  {
    id: '/',
    label: 'Introduction',
    level: 1
  },
  {
    id: '/docs/getting-started#whats-new-in-v3',
    label: 'What\'s new in v3?',
    level: 2
  },
  {
    id: '/docs/getting-started#reka-ui',
    label: 'Reka UI',
    level: 3
  },
  {
    id: '/docs/getting-started#tailwind-css',
    label: 'Tailwind CSS',
    level: 3
  },
  {
    id: '/docs/getting-started#tailwind-variants',
    label: 'Tailwind Variants',
    level: 3
  },
  {
    id: '/docs/getting-started/installation',
    label: 'Installation',
    level: 1
  }
]

function postFilter(searchTerm: string, items: any[]) {
  // Filter only first level items if no searchTerm
  if (!searchTerm) {
    return items?.filter(item => item.level === 1)
  }

  return items
}
</script>

<template>
  <UCommandPalette :groups="[{ id: 'files', items, postFilter }]" class="flex-1" />
</template>
입력을 시작하여 상위 레벨의 항목이 표시되는지 확인합니다.

사용자 정의 퓨즈 검색 기능

fuse prop을 사용하여 useFuse의 옵션을 무시할 수 있으며, 기본값은 다음과 같습니다.

{
  fuseOptions: {
    ignoreLocation: true,
    threshold: 0.1,
    keys: ['label', 'description', 'suffix']
  },
  resultLimit: 12,
  matchAllWhenSearchEmpty: true
}
fuseOptions는 Fuse.js의 옵션이며, resultLimit는 반환할 최대 결과 수이며, matchAllWhenSearchEmpty는 검색 용어가 비어 있을 때 모든 항목을 일치시키는 부울입니다.

예를 들어, { fuseOptions: { includeMatches: true } }를 설정하여 항목에서 검색 용어를 강조 표시할 수 있습니다.

No data
<script setup lang="ts">
const { data: users } = useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'command-palette-users',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  server: false
})
</script>

<template>
  <UCommandPalette
    :groups="[{ id: 'users', items: users || [] }]"
    :fuse="{ fuseOptions: { includeMatches: true } }"
    class="flex-1 h-80"
  />
</template>

가상화 지원: badge{label="4.1+" class="align-text-top"}

virtualize prop을 사용하여 큰 목록에 대해 부울 또는 { estimateSize: 32, overscan: 12 }와 같은 옵션이있는 개체로 가상화를 활성화합니다.

설정하면 Reka UI의 제한으로 인해 모든 그룹이 단일 리스트로 병합됩니다.
<script setup lang="ts">
import type { CommandPaletteItem } from '@nuxt/ui'

const items: CommandPaletteItem[] = Array(1000)
  .fill(0)
  .map((_, value) => ({
    label: `item-${value}`,
    value
  }))

const groups = [
  {
    id: 'items',
    items
  }
]
</script>

<template>
  <UCommandPalette
    virtualize
    :fuse="{ resultLimit: 1000 }"
    :groups="groups"
    class="flex-1 h-80"
  />
</template>

Popover 내부

Popover의 콘텐츠에서 CommandPalette 구성 요소를 사용할 수 있습니다.

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

const items = ref([
  {
    label: 'bug',
    value: 'bug',
    chip: {
      color: 'error'
    }
  },
  {
    label: 'feature',
    value: 'feature',
    chip: {
      color: 'success'
    }
  },
  {
    label: 'enhancement',
    value: 'enhancement',
    chip: {
      color: 'info'
    }
  }
] satisfies CommandPaletteItem[])

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

<template>
  <UPopover :content="{ side: 'right', align: 'start' }">
    <UButton
      icon="i-lucide-tag"
      label="Select labels"
      color="neutral"
      variant="subtle"
    />

    <template #content>
      <UCommandPalette
        v-model="label"
        multiple
        placeholder="Search labels..."
        :groups="[{ id: 'labels', items }]"
        :ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
      />
    </template>
  </UPopover>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteItem } from '@nuxt/ui'

const items = ref([
  {
    label: 'bug',
    value: 'bug',
    chip: {
      color: 'error'
    }
  },
  {
    label: 'feature',
    value: 'feature',
    chip: {
      color: 'success'
    }
  },
  {
    label: 'enhancement',
    value: 'enhancement',
    chip: {
      color: 'info'
    }
  }
] satisfies CommandPaletteItem[])

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

<template>
  <UPopover :content="{ side: 'right', align: 'start' }">
    <UButton
      icon="i-lucide-tag"
      label="Select labels"
      color="neutral"
      variant="subtle"
    />

    <template #content>
      <UCommandPalette
        v-model="label"
        multiple
        placeholder="Search labels..."
        :groups="[{ id: 'labels', items }]"
        :ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
      />
    </template>
  </UPopover>
</template>

within a modal 모드 내에서

Modal의 콘텐츠 내에서 CommandPalette 구성 요소를 사용할 수 있습니다.

<script setup lang="ts">
const searchTerm = ref('')

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'modal-command-palette-users',
  params: { q: searchTerm },
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  immediate: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || [],
  ignoreFilter: true
}])

function onOpen() {
  if (!users.value?.length) {
    execute()
  }
}
</script>

<template>
  <UModal @update:open="onOpen">
    <UButton
      label="Search users..."
      color="neutral"
      variant="subtle"
      icon="i-lucide-search"
    />

    <template #content>
      <UCommandPalette
        v-model:search-term="searchTerm"
        :loading="status === 'pending'"
        :groups="groups"
        placeholder="Search users..."
        class="h-80"
      />
    </template>
  </UModal>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'

const searchTerm = ref('')

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'modal-command-palette-users',
  params: { q: searchTerm },
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  immediate: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || [],
  ignoreFilter: true
}])

function onOpen() {
  if (!users.value?.length) {
    execute()
  }
}
</script>

<template>
  <UModal @update:open="onOpen">
    <UButton
      label="Search users..."
      color="neutral"
      variant="subtle"
      icon="i-lucide-search"
    />

    <template #content>
      <UCommandPalette
        v-model:search-term="searchTerm"
        :loading="status === 'pending'"
        :groups="groups"
        placeholder="Search users..."
        class="h-80"
      />
    </template>
  </UModal>
</template>
이 예에서는 useLazyFetch와 immediate: false를 사용하여 Modal이 열릴 때만 데이터를 가져옵니다.

within a drawer 드라이버 안에서

Drawer의 콘텐츠 내에서 CommandPalette 구성 요소를 사용할 수 있습니다.

<script setup lang="ts">
const searchTerm = ref('')

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'drawer-command-palette-users',
  params: { q: searchTerm },
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  immediate: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || [],
  ignoreFilter: true
}])

function onOpen() {
  if (!users.value?.length) {
    execute()
  }
}
</script>

<template>
  <UDrawer :handle="false" @update:open="onOpen">
    <UButton
      label="Search users..."
      color="neutral"
      variant="subtle"
      icon="i-lucide-search"
    />

    <template #content>
      <UCommandPalette
        v-model:search-term="searchTerm"
        :loading="status === 'pending'"
        :groups="groups"
        placeholder="Search users..."
        class="h-80"
      />
    </template>
  </UDrawer>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'

const searchTerm = ref('')

const { data: users, status, execute } = await useLazyFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'drawer-command-palette-users',
  params: { q: searchTerm },
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({ id: user.id, label: user.name, suffix: user.email, avatar: { src: `https://i.pravatar.cc/120?img=${user.id}`, loading: 'lazy' as const } })) || []
  },
  immediate: false
})

const groups = computed(() => [{
  id: 'users',
  label: searchTerm.value ? `Users matching “${searchTerm.value}”...` : 'Users',
  items: users.value || [],
  ignoreFilter: true
}])

function onOpen() {
  if (!users.value?.length) {
    execute()
  }
}
</script>

<template>
  <UDrawer :handle="false" @update:open="onOpen">
    <UButton
      label="Search users..."
      color="neutral"
      variant="subtle"
      icon="i-lucide-search"
    />

    <template #content>
      <UCommandPalette
        v-model:search-term="searchTerm"
        :loading="status === 'pending'"
        :groups="groups"
        placeholder="Search users..."
        class="h-80"
      />
    </template>
  </UDrawer>
</template>
이 예제에서는 useLazyFetch와 immediate: false를 사용하여 Drawer가 열릴 때만 데이터를 가져옵니다.

Listen 열린 상태

close Prop을 사용할 때 버튼을 클릭하면 update:open 이벤트를 들을 수 있습니다.

<script setup lang="ts">
const open = ref(false)

const users = [
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    to: 'https://github.com/benjamincanac',
    target: '_blank',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Hugo Richard',
    suffix: 'HugoRCD',
    to: 'https://github.com/HugoRCD',
    target: '_blank',
    avatar: {
      src: 'https://github.com/HugoRCD.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sébastien Chopin',
    suffix: 'atinux',
    to: 'https://github.com/atinux',
    target: '_blank',
    avatar: {
      src: 'https://github.com/atinux.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Romain Hamel',
    suffix: 'romhml',
    to: 'https://github.com/romhml',
    target: '_blank',
    avatar: {
      src: 'https://github.com/romhml.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sandro Circi',
    suffix: 'sandros94',
    to: 'https://github.com/sandros94',
    target: '_blank',
    avatar: {
      src: 'https://github.com/sandros94.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Jakub Michálek',
    suffix: 'J-Michalek',
    to: 'https://github.com/J-Michalek',
    target: '_blank',
    avatar: {
      src: 'https://github.com/J-Michalek.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Alex',
    suffix: 'hywax',
    to: 'https://github.com/hywax',
    target: '_blank',
    avatar: {
      src: 'https://github.com/hywax.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Maxime Pauvert',
    suffix: 'maximepvrt',
    to: 'https://github.com/maximepvrt',
    target: '_blank',
    avatar: {
      src: 'https://github.com/maximepvrt.png',
      loading: 'lazy' as const
    }
  }
]
</script>

<template>
  <UModal v-model:open="open">
    <UButton
      label="Search users..."
      color="neutral"
      variant="subtle"
      icon="i-lucide-search"
    />

    <template #content>
      <UCommandPalette close :groups="[{ id: 'users', items: users }]" @update:open="open = $event" />
    </template>
  </UModal>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const open = ref(false)

const users = [
  {
    label: 'Benjamin Canac',
    suffix: 'benjamincanac',
    to: 'https://github.com/benjamincanac',
    target: '_blank',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Hugo Richard',
    suffix: 'HugoRCD',
    to: 'https://github.com/HugoRCD',
    target: '_blank',
    avatar: {
      src: 'https://github.com/HugoRCD.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sébastien Chopin',
    suffix: 'atinux',
    to: 'https://github.com/atinux',
    target: '_blank',
    avatar: {
      src: 'https://github.com/atinux.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Romain Hamel',
    suffix: 'romhml',
    to: 'https://github.com/romhml',
    target: '_blank',
    avatar: {
      src: 'https://github.com/romhml.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Sandro Circi',
    suffix: 'sandros94',
    to: 'https://github.com/sandros94',
    target: '_blank',
    avatar: {
      src: 'https://github.com/sandros94.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Jakub Michálek',
    suffix: 'J-Michalek',
    to: 'https://github.com/J-Michalek',
    target: '_blank',
    avatar: {
      src: 'https://github.com/J-Michalek.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Alex',
    suffix: 'hywax',
    to: 'https://github.com/hywax',
    target: '_blank',
    avatar: {
      src: 'https://github.com/hywax.png',
      loading: 'lazy' as const
    }
  },
  {
    label: 'Maxime Pauvert',
    suffix: 'maximepvrt',
    to: 'https://github.com/maximepvrt',
    target: '_blank',
    avatar: {
      src: 'https://github.com/maximepvrt.png',
      loading: 'lazy' as const
    }
  }
]
</script>

<template>
  <UModal v-model:open="open">
    <UButton
      label="Search users..."
      color="neutral"
      variant="subtle"
      icon="i-lucide-search"
    />

    <template #content>
      <UCommandPalette close :groups="[{ id: 'users', items: users }]" @update:open="open = $event" />
    </template>
  </UModal>
</template>
이 기능은 예를 들어 Modal 내부에서 CommandPalette를 사용할 때 유용합니다.

바닥글 슬롯 포함

#footer 슬롯을 사용하여 CommandPalette의 맨 아래에 키보드 바로 가기 도움말 또는 추가 작업과 같은 사용자 정의 컨텐츠를 추가합니다.

<script setup lang="ts">
const groups = [
  {
    id: 'actions',
    items: [
      {
        label: 'Add new file',
        suffix: 'Create a new file in the current directory',
        icon: 'i-lucide-file-plus',
        kbds: ['meta', 'N']
      },
      {
        label: 'Add new folder',
        suffix: 'Create a new folder in the current directory',
        icon: 'i-lucide-folder-plus',
        kbds: ['meta', 'F']
      },
      {
        label: 'Search files',
        suffix: 'Search across all files in the project',
        icon: 'i-lucide-search',
        kbds: ['meta', 'P']
      },
      {
        label: 'Settings',
        suffix: 'Open application settings',
        icon: 'i-lucide-settings',
        kbds: ['meta', ',']
      }
    ]
  },
  {
    id: 'recent',
    label: 'Recent',
    items: [
      {
        label: 'project.vue',
        suffix: 'components/',
        icon: 'i-vscode-icons-file-type-vue'
      },
      {
        label: 'readme.md',
        suffix: 'docs/',
        icon: 'i-vscode-icons-file-type-markdown'
      },
      {
        label: 'package.json',
        suffix: 'root/',
        icon: 'i-vscode-icons-file-type-node'
      }
    ]
  }
]
</script>

<template>
  <UCommandPalette :groups="groups" class="flex-1 h-80">
    <template #footer>
      <div class="flex items-center justify-between gap-2">
        <UIcon name="i-simple-icons-nuxtdotjs" class="size-5 text-dimmed ml-1" />
        <div class="flex items-center gap-1">
          <UButton color="neutral" variant="ghost" label="Open Command" class="text-dimmed" size="xs">
            <template #trailing>
              <UKbd value="enter" />
            </template>
          </UButton>
          <USeparator orientation="vertical" class="h-4" />
          <UButton color="neutral" variant="ghost" label="Actions" class="text-dimmed" size="xs">
            <template #trailing>
              <UKbd value="meta" />
              <UKbd value="k" />
            </template>
          </UButton>
        </div>
      </div>
    </template>
  </UCommandPalette>
</template>

사용자 정의 슬롯 포함

slot 속성을 사용하여 특정 항목 또는 그룹을 사용자 정의합니다.

다음과 같은 슬롯에 액세스할 수 있습니다.

  • #{{ item.slot }}
  • #{{ item.slot }}-leading
  • #{{ item.slot }}-label
  • #{{ item.slot }}-trailing
  • #{{ group.slot }}
  • #{{ group.slot }}-leading
  • #{{ group.slot }}-label (- #{{ group.slot }}-label)
  • #{{ group.slot }}-trailing (- xph93xxph94x)
<script setup lang="ts">
const groups = [
  {
    id: 'settings',
    items: [
      {
        label: 'Profile',
        icon: 'i-lucide-user',
        kbds: ['meta', 'P']
      },
      {
        label: 'Billing',
        icon: 'i-lucide-credit-card',
        kbds: ['meta', 'B'],
        slot: 'billing' as const
      },
      {
        label: 'Notifications',
        icon: 'i-lucide-bell'
      },
      {
        label: 'Security',
        icon: 'i-lucide-lock'
      }
    ]
  },
  {
    id: 'users',
    label: 'Users',
    slot: 'users' as const,
    items: [
      {
        label: 'Benjamin Canac',
        suffix: 'benjamincanac',
        to: 'https://github.com/benjamincanac',
        target: '_blank'
      },
      {
        label: 'Romain Hamel',
        suffix: 'romhml',
        to: 'https://github.com/romhml',
        target: '_blank'
      },
      {
        label: 'Sébastien Chopin',
        suffix: 'atinux',
        to: 'https://github.com/atinux',
        target: '_blank'
      },
      {
        label: 'Hugo Richard',
        suffix: 'HugoRCD',
        to: 'https://github.com/HugoRCD',
        target: '_blank'
      },
      {
        label: 'Sandro Circi',
        suffix: 'sandros94',
        to: 'https://github.com/sandros94',
        target: '_blank'
      },
      {
        label: 'Daniel Roe',
        suffix: 'danielroe',
        to: 'https://github.com/danielroe',
        target: '_blank'
      },
      {
        label: 'Jakub Michálek',
        suffix: 'J-Michalek',
        to: 'https://github.com/J-Michalek',
        target: '_blank'
      },
      {
        label: 'Eugen Istoc',
        suffix: 'genu',
        to: 'https://github.com/genu',
        target: '_blank'
      }
    ]
  }
]
</script>

<template>
  <UCommandPalette :groups="groups" class="flex-1 h-80">
    <template #users-leading="{ item }">
      <UAvatar :src="`https://github.com/${item.suffix}.png`" size="2xs" loading="lazy" />
    </template>

    <template #billing-label="{ item }">
      <span class="font-medium text-primary">{{ item.label }}</span>

      <UBadge variant="subtle" size="sm">
        50% off
      </UBadge>
    </template>
  </UCommandPalette>
</template>
또한 #item, #item-leading, #item-label 및 #item-trailing 슬롯을 사용하여 모든 항목을 사용자 정의 할 수 있습니다.

API 파일

Props (### Props)

Prop Default Type
as
'div'
any

The element or component this component should render as.

size
'md'
"sm" | "md" | "xs" | "lg" | "xl"
icon
appConfig.ui.icons.search
any

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

trailingIcon
appConfig.ui.icons.search
any

The icon displayed on the right side of the input.

selectedIcon
appConfig.ui.icons.check
any

The icon displayed when an item is selected.

childrenIcon
appConfig.ui.icons.chevronRight
any

The icon displayed when an item has children.

placeholder
t('commandPalette.placeholder')
string

The placeholder text for the input.

autofocus
true
boolean

Automatically focus the input when component is mounted.

close
false
boolean | Omit<ButtonProps, LinkPropsKeys>

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

closeIcon
appConfig.ui.icons.close
any

The icon displayed in the close button.

back
true
boolean | Omit<ButtonProps, LinkPropsKeys>

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

backIcon
appConfig.ui.icons.arrowLeft
any

The icon displayed in the back button.

input
true
boolean | 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.

virtualize
false
boolean | { 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).

valueKey
undefined
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.

preserveGroupOrder
false
boolean

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

searchDelay
0
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.

multiple
boolean

Whether multiple options can be selected or not.

disabled
boolean

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

highlightOnHover
true
boolean

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.

loading
boolean

When true, the loading icon will be displayed.

loadingIcon
appConfig.ui.icons.loading
any

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; }

슬롯

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]

Theme 테마

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 '@nuxt/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'
          }
        }
      }
    })
  ]
})

변경 로그

No recent changes