SelectMenu

ComboboxGitHub
一个高级可搜索的选择元素。

用法

使用 v-model 指令控制 SelectMenu 的值,或使用 default-value prop 设置初始值,当你不需要控制其状态时。

使用此组件而非 Select,以利用 Reka UI 的Combobox组件,该组件提供搜索功能和多选功能。
此组件与 InputMenu 类似,但它使用 Select 而不是 Input,并且搜索功能在菜单内部。

items prop 用作字符串、数字或布尔值的数组

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" :items="items" class="w-48" />
</template>

您还可以传入一个包含以下属性的对象数组

  • label?: string
  • type?: "label" | "separator" | "item"
  • icon?: string
  • avatar?: AvatarProps
  • chip?: ChipProps
  • disabled?: boolean
  • onSelect?(e: Event): void
  • class?: any
  • ui?: { label?: ClassNameValue, separator?: ClassNameValue, item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue itemLeadingChipSize?: ClassNameValue, itemLeadingChip?: ClassNameValue, itemLabel?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingIcon?: ClassNameValue }
<script setup lang="ts">
const items = ref([
  {
    label: 'Backlog'
  },
  {
    label: 'Todo'
  },
  {
    label: 'In Progress'
  },
  {
    label: 'Done'
  }
])
const value = ref({
  label: 'Todo'
})
</script>

<template>
  <USelectMenu v-model="value" :items="items" class="w-48" />
</template>
Select 组件不同,SelectMenu 默认要求将整个对象传递给 v-model 指令或 default-value prop。

您还可以将数组的数组传递给 items prop,以显示分组的项。

<script setup lang="ts">
const items = ref([
  ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple'],
  ['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
])
const value = ref('Apple')
</script>

<template>
  <USelectMenu v-model="value" :items="items" class="w-48" />
</template>

值键

你可以通过使用 value-key prop 来绑定对象的单个属性,而不是整个对象。默认值为 undefined

<script setup lang="ts">
const items = ref([
  {
    label: 'Backlog',
    id: 'backlog'
  },
  {
    label: 'Todo',
    id: 'todo'
  },
  {
    label: 'In Progress',
    id: 'in_progress'
  },
  {
    label: 'Done',
    id: 'done'
  }
])
const value = ref('todo')
</script>

<template>
  <USelectMenu v-model="value" value-key="id" :items="items" class="w-48" />
</template>

多选

使用 multiple prop 允许多选,选定的项目将在触发器中以逗号分隔。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref(['Backlog', 'Todo'])
</script>

<template>
  <USelectMenu v-model="value" multiple :items="items" class="w-48" />
</template>
请务必向 default-value prop 或 v-model 指令传递一个数组。

占位符

使用 placeholder 属性设置占位文本。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
</script>

<template>
  <USelectMenu placeholder="Select status" :items="items" class="w-48" />
</template>

搜索输入

使用 search-input prop 自定义或隐藏搜索输入(传入 false 值)。

你可以从 Input 组件传递任何属性来自定义它。

<script setup lang="ts">
const items = ref([
  {
    label: 'Backlog',
    icon: 'i-lucide-circle-help'
  },
  {
    label: 'Todo',
    icon: 'i-lucide-circle-plus'
  },
  {
    label: 'In Progress',
    icon: 'i-lucide-circle-arrow-up'
  },
  {
    label: 'Done',
    icon: 'i-lucide-circle-check'
  }
])
const value = ref({
  label: 'Backlog',
  icon: 'i-lucide-circle-help'
})
</script>

<template>
  <USelectMenu
    v-model="value"
    :search-input="{
      placeholder: 'Filter...',
      icon: 'i-lucide-search'
    }"
    :items="items"
    class="w-48"
  />
</template>
你可以将 search-input prop 设置为 false 以隐藏搜索输入。

内容

使用 content prop 控制 SelectMenu 内容的渲染方式,例如其 alignside

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu
    v-model="value"
    :content="{
      align: 'center',
      side: 'bottom',
      sideOffset: 8
    }"
    :items="items"
    class="w-48"
  />
</template>

箭头

使用 arrow prop 在 SelectMenu 上显示箭头。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" arrow :items="items" class="w-48" />
</template>

颜色

使用 color prop 更改 SelectMenu 获得焦点时的环形颜色。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" color="neutral" highlight :items="items" class="w-48" />
</template>
highlight 属性在此用于显示焦点状态。当发生验证错误时,它会在内部使用。

变体

使用 variant prop 更改 SelectMenu 的变体。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" color="neutral" variant="subtle" :items="items" class="w-48" />
</template>

尺寸

使用 size prop 更改 SelectMenu 的大小。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" size="xl" :items="items" class="w-48" />
</template>

Icon

使用 icon prop 在 SelectMenu 中显示一个 图标

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" icon="i-lucide-search" size="md" :items="items" class="w-48" />
</template>

尾部图标

使用 trailing-icon prop 自定义尾随 图标。默认值为 i-lucide-chevron-down

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu
    v-model="value"
    trailing-icon="i-lucide-arrow-down"
    size="md"
    :items="items"
    class="w-48"
  />
</template>
你可以在 app.config.ts 中通过 ui.icons.chevronDown 键全局自定义此图标。
你可以在 vite.config.ts 中通过 ui.icons.chevronDown 键全局自定义此图标。

选中图标

使用 selected-icon prop 自定义选中项目时的图标。默认值为 i-lucide-check

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu
    v-model="value"
    selected-icon="i-lucide-flame"
    size="md"
    :items="items"
    class="w-48"
  />
</template>
你可以在 app.config.ts 中通过 ui.icons.check 键全局自定义此图标。
你可以在 vite.config.ts 中通过 ui.icons.check 键全局自定义此图标。

Avatar

使用 avatar prop 在 SelectMenu 中显示一个 头像

<script setup lang="ts">
const items = ref(['Nuxt', 'NuxtHub', 'NuxtLabs', 'Nuxt Modules', 'Nuxt Community'])
const value = ref('Nuxt')
</script>

<template>
  <USelectMenu
    v-model="value"
    :avatar="{
      src: 'https://github.com/nuxt.png'
    }"
    :items="items"
    class="w-48"
  />
</template>

加载中

使用 loading prop 在 SelectMenu 上显示加载图标。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" loading :items="items" class="w-48" />
</template>

加载图标

使用 loading-icon prop 自定义加载图标。默认值为 i-lucide-loader-circle

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" loading loading-icon="i-lucide-loader" :items="items" class="w-48" />
</template>
你可以在 app.config.ts 中通过 ui.icons.loading 键全局自定义此图标。
你可以在 vite.config.ts 中通过 ui.icons.loading 键全局自定义此图标。

禁用

使用 disabled prop 禁用 SelectMenu。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
</script>

<template>
  <USelectMenu disabled placeholder="Select status" :items="items" class="w-48" />
</template>

示例

使用项类型

你可以使用 type 属性配合 separator 来显示项目之间的分隔符,或者配合 label 来显示标签。

<script setup lang="ts">
const items = ref([
  {
    type: 'label',
    label: 'Fruits'
  },
  'Apple',
  'Banana',
  'Blueberry',
  'Grapes',
  'Pineapple',
  {
    type: 'separator'
  },
  {
    type: 'label',
    label: 'Vegetables'
  },
  'Aubergine',
  'Broccoli',
  'Carrot',
  'Courgette',
  'Leek'
])
const value = ref('Apple')
</script>

<template>
  <USelectMenu v-model="value" :items="items" class="w-48" />
</template>

项中带图标

你可以使用 icon 属性在项目中显示一个 图标

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

const items = ref([
  {
    label: 'Backlog',
    value: 'backlog',
    icon: 'i-lucide-circle-help'
  },
  {
    label: 'Todo',
    value: 'todo',
    icon: 'i-lucide-circle-plus'
  },
  {
    label: 'In Progress',
    value: 'in_progress',
    icon: 'i-lucide-circle-arrow-up'
  },
  {
    label: 'Done',
    value: 'done',
    icon: 'i-lucide-circle-check'
  }
] satisfies SelectMenuItem[])

const value = ref(items.value[0])
</script>

<template>
  <USelectMenu v-model="value" :icon="value?.icon" :items="items" class="w-48" />
</template>
您还可以使用 #leading 插槽显示选中的图标。

项中带头像

你可以使用 avatar 属性在项目中显示一个 头像

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

const items = ref([
  {
    label: 'benjamincanac',
    value: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      alt: 'benjamincanac'
    }
  },
  {
    label: 'romhml',
    value: 'romhml',
    avatar: {
      src: 'https://github.com/romhml.png',
      alt: 'romhml'
    }
  },
  {
    label: 'noook',
    value: 'noook',
    avatar: {
      src: 'https://github.com/noook.png',
      alt: 'noook'
    }
  },
  {
    label: 'sandros94',
    value: 'sandros94',
    avatar: {
      src: 'https://github.com/sandros94.png',
      alt: 'sandros94'
    }
  }
] satisfies SelectMenuItem[])

const value = ref(items.value[0])
</script>

<template>
  <USelectMenu v-model="value" :avatar="value?.avatar" :items="items" class="w-48" />
</template>
您还可以使用 #leading 插槽显示选中的头像。

项中带标签

你可以使用 chip 属性在项目中显示一个 标签

<script setup lang="ts">
import type { SelectMenuItem, ChipProps } 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 SelectMenuItem[])

const value = ref(items.value[0])
</script>

<template>
  <USelectMenu v-model="value" :items="items" class="w-48">
    <template #leading="{ modelValue, ui }">
      <UChip
        v-if="modelValue"
        v-bind="modelValue.chip"
        inset
        standalone
        :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
        :class="ui.itemLeadingChip()"
      />
    </template>
  </USelectMenu>
</template>
在此示例中,#leading 插槽用于显示选中的标签。

控制打开状态

你可以通过使用 default-open prop 或 v-model:open 指令来控制打开状态。

<script setup lang="ts">
const open = ref(false)
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')

defineShortcuts({
  o: () => open.value = !open.value
})
</script>

<template>
  <USelectMenu v-model="value" v-model:open="open" :items="items" class="w-48" />
</template>
在此示例中,利用 defineShortcuts,你可以通过按 O 键来切换 SelectMenu。

控制搜索词

使用 v-model:search-term 指令控制搜索词。

<script setup lang="ts">
const searchTerm = ref('D')
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu v-model="value" v-model:search-term="searchTerm" :items="items" class="w-48" />
</template>

带旋转图标

这是一个带有旋转图标的示例,该图标指示 SelectMenu 的打开状态。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')
</script>

<template>
  <USelectMenu
    v-model="value"
    :items="items"
    :ui="{
      trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
    }"
    class="w-48"
  />
</template>

创建项目

使用 create-item prop 允许用户添加不在预定义选项中的自定义值。

<script setup lang="ts">
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')

function onCreate(item: string) {
  items.value.push(item)

  value.value = item
}
</script>

<template>
  <USelectMenu
    v-model="value"
    create-item
    :items="items"
    class="w-48"
    @create="onCreate"
  />
</template>
默认情况下,当未找到匹配项时会显示创建选项。将其设置为 always,即使存在相似值也会显示。
使用 @create 事件来处理项目的创建。你将收到事件和项目作为参数。

带获取的项

你可以从 API 获取项目并在 SelectMenu 中使用它们。

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

const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'typicode-users',
  transform: (data: { id: number, name: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
    }))
  },
  lazy: true
})
</script>

<template>
  <USelectMenu
    :items="users"
    :loading="status === 'pending'"
    icon="i-lucide-user"
    placeholder="Select user"
    class="w-48"
  >
    <template #leading="{ modelValue, ui }">
      <UAvatar
        v-if="modelValue"
        v-bind="modelValue.avatar"
        :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
        :class="ui.leadingAvatar()"
      />
    </template>
  </USelectMenu>
</template>

带忽略过滤器

ignore-filter prop 设置为 true 以禁用内部搜索并使用你自己的搜索逻辑。

<script setup lang="ts">
import { refDebounced } from '@vueuse/core'
import type { AvatarProps } from '@nuxt/ui'

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

const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
  params: { q: searchTermDebounced },
  transform: (data: { id: number, name: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
    }))
  },
  lazy: true
})
</script>

<template>
  <USelectMenu
    v-model:search-term="searchTerm"
    :items="users"
    :loading="status === 'pending'"
    ignore-filter
    icon="i-lucide-user"
    placeholder="Select user"
    class="w-48"
  >
    <template #leading="{ modelValue, ui }">
      <UAvatar
        v-if="modelValue"
        v-bind="modelValue.avatar"
        :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
        :class="ui.leadingAvatar()"
      />
    </template>
  </USelectMenu>
</template>
此示例使用refDebounced来防抖 API 调用。

带过滤字段

使用 filter-fields prop,传入要过滤的字段数组。默认值为 [labelKey]

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

const { data: users, status } = await useFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'typicode-users-email',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      email: user.email,
      value: String(user.id),
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
    }))
  },
  lazy: true
})
</script>

<template>
  <USelectMenu
    :items="users"
    :loading="status === 'pending'"
    :filter-fields="['label', 'email']"
    icon="i-lucide-user"
    placeholder="Select user"
    class="w-80"
  >
    <template #leading="{ modelValue, ui }">
      <UAvatar
        v-if="modelValue"
        v-bind="modelValue.avatar"
        :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
        :class="ui.leadingAvatar()"
      />
    </template>

    <template #item-label="{ item }">
      {{ item.label }}

      <span class="text-muted">
        {{ item.email }}
      </span>
    </template>
  </USelectMenu>
</template>

内容全宽

您可以使用 ui.content 键将内容扩展到其项的完整宽度。

<script setup lang="ts">
const { data: users } = await useFetch('https://jsonplaceholder.typicode.com/users', {
  key: 'typicode-users-email',
  transform: (data: { id: number, name: string, email: string }[]) => {
    return data?.map(user => ({
      label: user.name,
      value: String(user.id),
      email: user.email,
      avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
    }))
  },
  lazy: true
})
</script>

<template>
  <USelectMenu
    :items="users"
    icon="i-lucide-user"
    placeholder="Select user"
    :ui="{ content: 'min-w-fit' }"
    class="w-48"
  >
    <template #item-label="{ item }">
      {{ item.label }}

      <span class="text-muted">
        {{ item.email }}
      </span>
    </template>
  </USelectMenu>
</template>
您也可以在 app.config.ts 中全局更改内容宽度
export default defineAppConfig({
  ui: {
    selectMenu: {
      slots: {
        content: 'min-w-fit'
      }
    }
  }
})

作为国家/地区选择器

此示例演示了如何将 SelectMenu 用作国家/地区选择器,并实现了惰性加载——只有在菜单打开时才获取国家/地区数据。

<script setup lang="ts">
const { data: countries, status, execute } = await useLazyFetch<{
  name: string
  code: string
  emoji: string
}[]>('/api/countries.json', {
  immediate: false
})

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

<template>
  <USelectMenu
    :items="countries"
    :loading="status === 'pending'"
    label-key="name"
    :search-input="{ icon: 'i-lucide-search' }"
    placeholder="Select country"
    class="w-48"
    @update:open="onOpen"
  >
    <template #leading="{ modelValue, ui }">
      <span v-if="modelValue" class="size-5 text-center">
        {{ modelValue?.emoji }}
      </span>
      <UIcon v-else name="i-lucide-earth" :class="ui.leadingIcon()" />
    </template>
    <template #item-leading="{ item }">
      <span class="size-5 text-center">
        {{ item.emoji }}
      </span>
    </template>
  </USelectMenu>
</template>

API

属性

属性默认值类型
id

string

占位符

string

选择框为空时的占位文本。

searchInput

true

boolean | InputProps<AcceptableValue>

是否显示搜索输入框。可以是对象,用于向输入框传递额外的 prop。例如:{ placeholder: 'Search...', variant: 'none' }

颜色

'primary'

"error" | "primary" | "secondary" | "success" | "info" | "warning | "neutral"

变体

'outline'

"outline" | "soft" | "subtle" | "ghost" | "none"

尺寸

'md'

"sm" | "md" | "xs" | "lg | "xl"

required

boolean

trailingIcon

appConfig.ui.icons.chevronDown

string

用于打开菜单的图标。

selectedIcon

appConfig.ui.icons.check

string

选中项时显示的图标。

内容

{ side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }

Omit<ComboboxContentProps, "asChild" | "as" | "forceMount"> & Partial<EmitsToProps<DismissableLayerEmits>>

菜单的内容。

箭头

false

boolean | Omit<ComboboxArrowProps, "asChild" | "as">

在菜单旁边显示一个箭头。

portal

true

string | false | true | HTMLElement

在 portal 中渲染菜单。

valueKey

undefined

string | number

items 是一个对象数组时,选择用作值的字段而不是对象本身。

labelKey

'label'

undefined

items 是对象数组时,选择用作标签的字段。

items

SelectMenuItem[] | SelectMenuItem[][]

defaultValue

any

SelectMenu 首次渲染时的值。当你不需要控制 SelectMenu 的状态时使用。

modelValue

any

SelectMenu 的受控值。可以通过 v-model 进行绑定。

multiple

boolean

是否可以选择多个选项。

高亮

boolean

高亮环形颜色,如同焦点状态。

createItem

false

boolean | "always" | { position?: "top" | "bottom" ; when?: "always" | "empty" | undefined; } | undefined

确定是否可以添加选项中不存在的自定义用户输入。

filterFields

[labelKey]

string[]

用于筛选项目的字段。

ignoreFilter

false

boolean

true时,禁用默认过滤器,这对于自定义过滤(useAsyncData, useFetch, etc.)很有用。

autofocus

boolean

autofocusDelay

0

number

open

boolean

Combobox 的受控打开状态。可以通过 v-model:open 绑定。

defaultOpen

boolean

Combobox 初次渲染时的打开状态。
当您不需要控制其打开状态时使用。

已禁用

boolean

当为 true 时,阻止用户与列表框交互

name

string

字段的名称。作为名称/值对的一部分随其所属表单提交。

resetSearchTermOnBlur

true

boolean

当 Combobox 输入框失焦时,是否重置搜索词。

resetSearchTermOnSelect

true

boolean

当 Combobox 选中值时,是否重置搜索词。

highlightOnHover

boolean

true 时,鼠标悬停在项目上会触发高亮显示。

图标

string

根据 leadingtrailing 属性显示图标。

avatar

AvatarProps

在左侧显示头像。

前置

boolean

当为 true 时,图标将显示在左侧。

leadingIcon

string

在左侧显示图标。

尾部

boolean

当为 true 时,图标将显示在右侧。

加载中

boolean

当为 true 时,将显示加载图标。

loadingIcon

appConfig.ui.icons.loading

string

loading 属性为 true 时的图标。

搜索词

''

string

ui

{ base?: ClassNameValue; leading?: ClassNameValue; leadingIcon?: ClassNameValue; leadingAvatar?: ClassNameValue; leadingAvatarSize?: ClassNameValue; trailing?: ClassNameValue; trailingIcon?: ClassNameValue; value?: ClassNameValue; placeholder?: ClassNameValue; arrow?: ClassNameValue; content?: ClassNameValue; viewport?: ClassNameValue; group?: ClassNameValue; empty?: ClassNameValue; label?: ClassNameValue; separator?: ClassNameValue; item?: ClassNameValue; itemLeadingIcon?: ClassNameValue; itemLeadingAvatar?: ClassNameValue; itemLeadingAvatarSize?: ClassNameValue; itemLeadingChip?: ClassNameValue; itemLeadingChipSize?: ClassNameValue; itemTrailing?: ClassNameValue; itemTrailingIcon?: ClassNameValue; itemLabel?: ClassNameValue; input?: ClassNameValue; focusScope?: ClassNameValue; }

插槽

插槽类型
前置

{ modelValue?: any; open: boolean; ui: {}; }

default

{ modelValue?: any; open: boolean; }

尾部

{ modelValue?: any; open: boolean; ui: {}; }

{ searchTerm?: string | undefined; }

item

{ item: SelectMenuItem; index: number; }

item-leading

{ item: SelectMenuItem; index: number; }

item-label

{ item: SelectMenuItem; index: number; }

item-trailing

{ item: SelectMenuItem; index: number; }

content-top

{}

content-bottom

{}

create-item-label

{ item: string; }

事件

事件类型
blur

[payload: FocusEvent]

change

[payload: Event]

focus

[payload: FocusEvent]

update:open

[value: boolean]

create

[item: string]

高亮

[payload: { ref: HTMLElement; value: any; } | undefined]

update:modelValue

[payload: any]

update:searchTerm

[value: string]

可访问属性

通过模板引用访问组件时,您可以使用以下内容:

名称类型
triggerRefRef<InstanceType<typeof ComboboxTrigger> | null>

主题

app.config.ts
export default defineAppConfig({
  ui: {
    selectMenu: {
      slots: {
        base: [
          'relative group rounded-md inline-flex items-center focus:outline-none disabled:cursor-not-allowed disabled:opacity-75',
          'transition-colors'
        ],
        leading: 'absolute inset-y-0 start-0 flex items-center',
        leadingIcon: 'shrink-0 text-dimmed',
        leadingAvatar: 'shrink-0',
        leadingAvatarSize: '',
        trailing: 'absolute inset-y-0 end-0 flex items-center',
        trailingIcon: 'shrink-0 text-dimmed',
        value: 'truncate pointer-events-none',
        placeholder: 'truncate text-dimmed',
        arrow: 'fill-default',
        content: [
          'max-h-60 w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-select-content-transform-origin) pointer-events-auto flex flex-col',
          'origin-(--reka-combobox-content-transform-origin) w-(--reka-combobox-trigger-width)'
        ],
        viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1',
        group: 'p-1 isolate',
        empty: 'text-center text-muted',
        label: 'font-semibold text-highlighted',
        separator: '-mx-1 my-1 h-px bg-border',
        item: [
          'group relative w-full flex items-center select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
          'transition-colors before:transition-colors'
        ],
        itemLeadingIcon: [
          'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
          'transition-colors'
        ],
        itemLeadingAvatar: 'shrink-0',
        itemLeadingAvatarSize: '',
        itemLeadingChip: 'shrink-0',
        itemLeadingChipSize: '',
        itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
        itemTrailingIcon: 'shrink-0',
        itemLabel: 'truncate',
        input: 'border-b border-default',
        focusScope: 'flex flex-col min-h-0'
      },
      variants: {
        buttonGroup: {
          horizontal: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]',
          vertical: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]'
        },
        size: {
          xs: {
            base: 'px-2 py-1 text-xs gap-1',
            leading: 'ps-2',
            trailing: 'pe-2',
            leadingIcon: 'size-4',
            leadingAvatarSize: '3xs',
            trailingIcon: 'size-4',
            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',
            itemTrailingIcon: 'size-4',
            empty: 'p-1 text-xs'
          },
          sm: {
            base: 'px-2.5 py-1.5 text-xs gap-1.5',
            leading: 'ps-2.5',
            trailing: 'pe-2.5',
            leadingIcon: 'size-4',
            leadingAvatarSize: '3xs',
            trailingIcon: 'size-4',
            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',
            itemTrailingIcon: 'size-4',
            empty: 'p-1.5 text-xs'
          },
          md: {
            base: 'px-2.5 py-1.5 text-sm gap-1.5',
            leading: 'ps-2.5',
            trailing: 'pe-2.5',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs',
            trailingIcon: 'size-5',
            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',
            itemTrailingIcon: 'size-5',
            empty: 'p-1.5 text-sm'
          },
          lg: {
            base: 'px-3 py-2 text-sm gap-2',
            leading: 'ps-3',
            trailing: 'pe-3',
            leadingIcon: 'size-5',
            leadingAvatarSize: '2xs',
            trailingIcon: 'size-5',
            label: 'p-2 text-xs gap-2',
            item: 'p-2 text-sm gap-2',
            itemLeadingIcon: 'size-5',
            itemLeadingAvatarSize: '2xs',
            itemLeadingChip: 'size-5',
            itemLeadingChipSize: 'md',
            itemTrailingIcon: 'size-5',
            empty: 'p-2 text-sm'
          },
          xl: {
            base: 'px-3 py-2 text-base gap-2',
            leading: 'ps-3',
            trailing: 'pe-3',
            leadingIcon: 'size-6',
            leadingAvatarSize: 'xs',
            trailingIcon: 'size-6',
            label: 'p-2 text-sm gap-2',
            item: 'p-2 text-base gap-2',
            itemLeadingIcon: 'size-6',
            itemLeadingAvatarSize: 'xs',
            itemLeadingChip: 'size-6',
            itemLeadingChipSize: 'lg',
            itemTrailingIcon: 'size-6',
            empty: 'p-2 text-base'
          }
        },
        variant: {
          outline: 'text-highlighted bg-default ring ring-inset ring-accented',
          soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
          subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
          ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
          none: 'text-highlighted bg-transparent'
        },
        color: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        leading: {
          true: ''
        },
        trailing: {
          true: ''
        },
        loading: {
          true: ''
        },
        highlight: {
          true: ''
        },
        type: {
          file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          variant: [
            'outline',
            'subtle'
          ],
          class: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary'
        },
        {
          color: 'primary',
          highlight: true,
          class: 'ring ring-inset ring-primary'
        },
        {
          color: 'neutral',
          variant: [
            'outline',
            'subtle'
          ],
          class: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-inverted'
        },
        {
          color: 'neutral',
          highlight: true,
          class: 'ring ring-inset ring-inverted'
        },
        {
          leading: true,
          size: 'xs',
          class: 'ps-7'
        },
        {
          leading: true,
          size: 'sm',
          class: 'ps-8'
        },
        {
          leading: true,
          size: 'md',
          class: 'ps-9'
        },
        {
          leading: true,
          size: 'lg',
          class: 'ps-10'
        },
        {
          leading: true,
          size: 'xl',
          class: 'ps-11'
        },
        {
          trailing: true,
          size: 'xs',
          class: 'pe-7'
        },
        {
          trailing: true,
          size: 'sm',
          class: 'pe-8'
        },
        {
          trailing: true,
          size: 'md',
          class: 'pe-9'
        },
        {
          trailing: true,
          size: 'lg',
          class: 'pe-10'
        },
        {
          trailing: true,
          size: 'xl',
          class: 'pe-11'
        },
        {
          loading: true,
          leading: true,
          class: {
            leadingIcon: 'animate-spin'
          }
        },
        {
          loading: true,
          leading: false,
          trailing: true,
          class: {
            trailingIcon: 'animate-spin'
          }
        }
      ],
      defaultVariants: {
        size: 'md',
        color: 'primary',
        variant: 'outline'
      }
    }
  }
})
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: {
        selectMenu: {
          slots: {
            base: [
              'relative group rounded-md inline-flex items-center focus:outline-none disabled:cursor-not-allowed disabled:opacity-75',
              'transition-colors'
            ],
            leading: 'absolute inset-y-0 start-0 flex items-center',
            leadingIcon: 'shrink-0 text-dimmed',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            trailing: 'absolute inset-y-0 end-0 flex items-center',
            trailingIcon: 'shrink-0 text-dimmed',
            value: 'truncate pointer-events-none',
            placeholder: 'truncate text-dimmed',
            arrow: 'fill-default',
            content: [
              'max-h-60 w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-select-content-transform-origin) pointer-events-auto flex flex-col',
              'origin-(--reka-combobox-content-transform-origin) w-(--reka-combobox-trigger-width)'
            ],
            viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1',
            group: 'p-1 isolate',
            empty: 'text-center text-muted',
            label: 'font-semibold text-highlighted',
            separator: '-mx-1 my-1 h-px bg-border',
            item: [
              'group relative w-full flex items-center select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
              'transition-colors before:transition-colors'
            ],
            itemLeadingIcon: [
              'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
              'transition-colors'
            ],
            itemLeadingAvatar: 'shrink-0',
            itemLeadingAvatarSize: '',
            itemLeadingChip: 'shrink-0',
            itemLeadingChipSize: '',
            itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
            itemTrailingIcon: 'shrink-0',
            itemLabel: 'truncate',
            input: 'border-b border-default',
            focusScope: 'flex flex-col min-h-0'
          },
          variants: {
            buttonGroup: {
              horizontal: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]',
              vertical: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]'
            },
            size: {
              xs: {
                base: 'px-2 py-1 text-xs gap-1',
                leading: 'ps-2',
                trailing: 'pe-2',
                leadingIcon: 'size-4',
                leadingAvatarSize: '3xs',
                trailingIcon: 'size-4',
                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',
                itemTrailingIcon: 'size-4',
                empty: 'p-1 text-xs'
              },
              sm: {
                base: 'px-2.5 py-1.5 text-xs gap-1.5',
                leading: 'ps-2.5',
                trailing: 'pe-2.5',
                leadingIcon: 'size-4',
                leadingAvatarSize: '3xs',
                trailingIcon: 'size-4',
                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',
                itemTrailingIcon: 'size-4',
                empty: 'p-1.5 text-xs'
              },
              md: {
                base: 'px-2.5 py-1.5 text-sm gap-1.5',
                leading: 'ps-2.5',
                trailing: 'pe-2.5',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs',
                trailingIcon: 'size-5',
                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',
                itemTrailingIcon: 'size-5',
                empty: 'p-1.5 text-sm'
              },
              lg: {
                base: 'px-3 py-2 text-sm gap-2',
                leading: 'ps-3',
                trailing: 'pe-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs',
                trailingIcon: 'size-5',
                label: 'p-2 text-xs gap-2',
                item: 'p-2 text-sm gap-2',
                itemLeadingIcon: 'size-5',
                itemLeadingAvatarSize: '2xs',
                itemLeadingChip: 'size-5',
                itemLeadingChipSize: 'md',
                itemTrailingIcon: 'size-5',
                empty: 'p-2 text-sm'
              },
              xl: {
                base: 'px-3 py-2 text-base gap-2',
                leading: 'ps-3',
                trailing: 'pe-3',
                leadingIcon: 'size-6',
                leadingAvatarSize: 'xs',
                trailingIcon: 'size-6',
                label: 'p-2 text-sm gap-2',
                item: 'p-2 text-base gap-2',
                itemLeadingIcon: 'size-6',
                itemLeadingAvatarSize: 'xs',
                itemLeadingChip: 'size-6',
                itemLeadingChipSize: 'lg',
                itemTrailingIcon: 'size-6',
                empty: 'p-2 text-base'
              }
            },
            variant: {
              outline: 'text-highlighted bg-default ring ring-inset ring-accented',
              soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
              subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
              ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
              none: 'text-highlighted bg-transparent'
            },
            color: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            leading: {
              true: ''
            },
            trailing: {
              true: ''
            },
            loading: {
              true: ''
            },
            highlight: {
              true: ''
            },
            type: {
              file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
            }
          },
          compoundVariants: [
            {
              color: 'primary',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary'
            },
            {
              color: 'primary',
              highlight: true,
              class: 'ring ring-inset ring-primary'
            },
            {
              color: 'neutral',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-inverted'
            },
            {
              color: 'neutral',
              highlight: true,
              class: 'ring ring-inset ring-inverted'
            },
            {
              leading: true,
              size: 'xs',
              class: 'ps-7'
            },
            {
              leading: true,
              size: 'sm',
              class: 'ps-8'
            },
            {
              leading: true,
              size: 'md',
              class: 'ps-9'
            },
            {
              leading: true,
              size: 'lg',
              class: 'ps-10'
            },
            {
              leading: true,
              size: 'xl',
              class: 'ps-11'
            },
            {
              trailing: true,
              size: 'xs',
              class: 'pe-7'
            },
            {
              trailing: true,
              size: 'sm',
              class: 'pe-8'
            },
            {
              trailing: true,
              size: 'md',
              class: 'pe-9'
            },
            {
              trailing: true,
              size: 'lg',
              class: 'pe-10'
            },
            {
              trailing: true,
              size: 'xl',
              class: 'pe-11'
            },
            {
              loading: true,
              leading: true,
              class: {
                leadingIcon: 'animate-spin'
              }
            },
            {
              loading: true,
              leading: false,
              trailing: true,
              class: {
                trailingIcon: 'animate-spin'
              }
            }
          ],
          defaultVariants: {
            size: 'md',
            color: 'primary',
            variant: 'outline'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        selectMenu: {
          slots: {
            base: [
              'relative group rounded-md inline-flex items-center focus:outline-none disabled:cursor-not-allowed disabled:opacity-75',
              'transition-colors'
            ],
            leading: 'absolute inset-y-0 start-0 flex items-center',
            leadingIcon: 'shrink-0 text-dimmed',
            leadingAvatar: 'shrink-0',
            leadingAvatarSize: '',
            trailing: 'absolute inset-y-0 end-0 flex items-center',
            trailingIcon: 'shrink-0 text-dimmed',
            value: 'truncate pointer-events-none',
            placeholder: 'truncate text-dimmed',
            arrow: 'fill-default',
            content: [
              'max-h-60 w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-select-content-transform-origin) pointer-events-auto flex flex-col',
              'origin-(--reka-combobox-content-transform-origin) w-(--reka-combobox-trigger-width)'
            ],
            viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1',
            group: 'p-1 isolate',
            empty: 'text-center text-muted',
            label: 'font-semibold text-highlighted',
            separator: '-mx-1 my-1 h-px bg-border',
            item: [
              'group relative w-full flex items-center select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50',
              'transition-colors before:transition-colors'
            ],
            itemLeadingIcon: [
              'shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default',
              'transition-colors'
            ],
            itemLeadingAvatar: 'shrink-0',
            itemLeadingAvatarSize: '',
            itemLeadingChip: 'shrink-0',
            itemLeadingChipSize: '',
            itemTrailing: 'ms-auto inline-flex gap-1.5 items-center',
            itemTrailingIcon: 'shrink-0',
            itemLabel: 'truncate',
            input: 'border-b border-default',
            focusScope: 'flex flex-col min-h-0'
          },
          variants: {
            buttonGroup: {
              horizontal: 'not-only:first:rounded-e-none not-only:last:rounded-s-none not-last:not-first:rounded-none focus-visible:z-[1]',
              vertical: 'not-only:first:rounded-b-none not-only:last:rounded-t-none not-last:not-first:rounded-none focus-visible:z-[1]'
            },
            size: {
              xs: {
                base: 'px-2 py-1 text-xs gap-1',
                leading: 'ps-2',
                trailing: 'pe-2',
                leadingIcon: 'size-4',
                leadingAvatarSize: '3xs',
                trailingIcon: 'size-4',
                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',
                itemTrailingIcon: 'size-4',
                empty: 'p-1 text-xs'
              },
              sm: {
                base: 'px-2.5 py-1.5 text-xs gap-1.5',
                leading: 'ps-2.5',
                trailing: 'pe-2.5',
                leadingIcon: 'size-4',
                leadingAvatarSize: '3xs',
                trailingIcon: 'size-4',
                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',
                itemTrailingIcon: 'size-4',
                empty: 'p-1.5 text-xs'
              },
              md: {
                base: 'px-2.5 py-1.5 text-sm gap-1.5',
                leading: 'ps-2.5',
                trailing: 'pe-2.5',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs',
                trailingIcon: 'size-5',
                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',
                itemTrailingIcon: 'size-5',
                empty: 'p-1.5 text-sm'
              },
              lg: {
                base: 'px-3 py-2 text-sm gap-2',
                leading: 'ps-3',
                trailing: 'pe-3',
                leadingIcon: 'size-5',
                leadingAvatarSize: '2xs',
                trailingIcon: 'size-5',
                label: 'p-2 text-xs gap-2',
                item: 'p-2 text-sm gap-2',
                itemLeadingIcon: 'size-5',
                itemLeadingAvatarSize: '2xs',
                itemLeadingChip: 'size-5',
                itemLeadingChipSize: 'md',
                itemTrailingIcon: 'size-5',
                empty: 'p-2 text-sm'
              },
              xl: {
                base: 'px-3 py-2 text-base gap-2',
                leading: 'ps-3',
                trailing: 'pe-3',
                leadingIcon: 'size-6',
                leadingAvatarSize: 'xs',
                trailingIcon: 'size-6',
                label: 'p-2 text-sm gap-2',
                item: 'p-2 text-base gap-2',
                itemLeadingIcon: 'size-6',
                itemLeadingAvatarSize: 'xs',
                itemLeadingChip: 'size-6',
                itemLeadingChipSize: 'lg',
                itemTrailingIcon: 'size-6',
                empty: 'p-2 text-base'
              }
            },
            variant: {
              outline: 'text-highlighted bg-default ring ring-inset ring-accented',
              soft: 'text-highlighted bg-elevated/50 hover:bg-elevated focus:bg-elevated disabled:bg-elevated/50',
              subtle: 'text-highlighted bg-elevated ring ring-inset ring-accented',
              ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
              none: 'text-highlighted bg-transparent'
            },
            color: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            leading: {
              true: ''
            },
            trailing: {
              true: ''
            },
            loading: {
              true: ''
            },
            highlight: {
              true: ''
            },
            type: {
              file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
            }
          },
          compoundVariants: [
            {
              color: 'primary',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary'
            },
            {
              color: 'primary',
              highlight: true,
              class: 'ring ring-inset ring-primary'
            },
            {
              color: 'neutral',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-inverted'
            },
            {
              color: 'neutral',
              highlight: true,
              class: 'ring ring-inset ring-inverted'
            },
            {
              leading: true,
              size: 'xs',
              class: 'ps-7'
            },
            {
              leading: true,
              size: 'sm',
              class: 'ps-8'
            },
            {
              leading: true,
              size: 'md',
              class: 'ps-9'
            },
            {
              leading: true,
              size: 'lg',
              class: 'ps-10'
            },
            {
              leading: true,
              size: 'xl',
              class: 'ps-11'
            },
            {
              trailing: true,
              size: 'xs',
              class: 'pe-7'
            },
            {
              trailing: true,
              size: 'sm',
              class: 'pe-8'
            },
            {
              trailing: true,
              size: 'md',
              class: 'pe-9'
            },
            {
              trailing: true,
              size: 'lg',
              class: 'pe-10'
            },
            {
              trailing: true,
              size: 'xl',
              class: 'pe-11'
            },
            {
              loading: true,
              leading: true,
              class: {
                leadingIcon: 'animate-spin'
              }
            },
            {
              loading: true,
              leading: false,
              trailing: true,
              class: {
                trailingIcon: 'animate-spin'
              }
            }
          ],
          defaultVariants: {
            size: 'md',
            color: 'primary',
            variant: 'outline'
          }
        }
      }
    })
  ]
})
为便于阅读,compoundVariants 中的某些颜色已省略。请在 GitHub 上查看源代码。