Select

选择GitHub
从选项列表中选择的选择元素。

用法

使用v-model指令来控制Select的值,或在不需要控制其状态时使用default-value属性来设置初始值。

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

<template>
  <USelect v-model="value" :items="items" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <USelect v-model="value" :items="items" />
</template>

项目

将items属性用作字符串、数字或布尔值的数组:

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

<template>
  <USelect v-model="value" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

您也可以传递具有下列属性的物件数组:

045 x的地址 051 x年12月27日星期一 058x-059x-056x-057x-058x-056x-057x-058x 065 x年060月062日061日066日063日064日065 x年065 x年065 x月065 x日065 x年065 x月065 x日 072 x年07月07日星期一 079 x年07月08日星期一 083x-083x 086 x年12月15日星期一 089 x年12月27日星期一

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

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

<template>
  <USelect v-model="value" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectItem } from '@nuxt/ui'

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

<template>
  <USelect v-model="value" :items="items" class="w-48" />
</template>
使用物件时,您必须在v-model指示词或default-value属性中指涉物件的value属性。

您也可以将数组的数组传递给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>
  <USelect v-model="value" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

值键

您可以使用value-key属性来变更用来设定值的属性。预设为value。

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

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

<template>
  <USelect v-model="value" value-key="id" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectItem } from '@nuxt/ui'

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

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

多重

使用multiple道具可进行多项选择,所选项目将在触发器中以逗号分隔。

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

<template>
  <USelect v-model="value" multiple :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <USelect v-model="value" multiple :items="items" class="w-48" />
</template>
请确定将数组传递至default-value属性或v-model指示词。

占位符

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

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

<template>
  <USelect placeholder="Select status" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

内容

使用content属性控制Select内容的呈现方式,例如align或side。

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

<template>
  <USelect
    v-model="value"
    :content="{
      align: 'center',
      side: 'bottom',
      sideOffset: 8
    }"
    :items="items"
    class="w-48"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <USelect
    v-model="value"
    :content="{
      align: 'center',
      side: 'bottom',
      sideOffset: 8
    }"
    :items="items"
    class="w-48"
  />
</template>
这些选项仅在content.position为popper(默认值)时适用。

位置:badge{label="4.7+" class="align-text-top"}

使用content.position属性来控制Select内容相对于触发器的定位方式。将其设置为popper,这会像其他弹出窗口一样定位内容。将其设置为item-aligned可将内容与所选项目对齐(类似于本机macOS菜单)。

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

<template>
  <USelect
    v-model="value"
    :content="{
      position: 'item-aligned'
    }"
    :items="items"
    class="w-48"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <USelect
    v-model="value"
    :content="{
      position: 'item-aligned'
    }"
    :items="items"
    class="w-48"
  />
</template>

Arrow

使用arrow道具在Select上显示箭头。

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

<template>
  <USelect v-model="value" arrow :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

Color

使用color道具来改变选择时的环颜色。

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

<template>
  <USelect v-model="value" color="neutral" highlight :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

Variant

使用variant prop更改Select的变体。

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

<template>
  <USelect v-model="value" color="neutral" variant="subtle" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

Size

使用size道具来更改Select的大小。

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

<template>
  <USelect v-model="value" size="xl" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

Icon

使用icon道具在Select中显示Icon。

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

<template>
  <USelect v-model="value" icon="i-lucide-search" size="md" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

拖尾图标

使用trailing-icon prop将尾随的Icon.xml自定义为i-lucide-chevron-down。

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

<template>
  <USelect
    v-model="value"
    trailing-icon="i-lucide-arrow-down"
    size="md"
    :items="items"
    class="w-48"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <USelect
    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道具自定义选中某个项目时的图标。将其转换为i-lucide-check。

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

<template>
  <USelect v-model="value" selected-icon="i-lucide-flame" size="md" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

Avatar

使用avatar道具在Select内显示Avatar。

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

<template>
  <USelect
    v-model="value"
    :avatar="{
      src: 'https://github.com/nuxt.png',
      loading: 'lazy'
    }"
    :items="items"
    class="w-48"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

加载中

使用loading道具在Select上显示一个加载图标。

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

<template>
  <USelect v-model="value" loading :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

加载图标

使用loading-icon道具自定义加载图标. i-lucide-loader-circle。

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

<template>
  <USelect v-model="value" loading loading-icon="i-lucide-loader" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

<template>
  <USelect 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禁用Select。

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

<template>
  <USelect disabled placeholder="Select status" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

示例

带项目类型

您可以将type属性与separator一起使用,以显示项之间的分隔符,或将label用于显示标签。

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

const items = ref<SelectItem[]>([
  {
    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>
  <USelect v-model="value" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectItem } from '@nuxt/ui'

const items = ref<SelectItem[]>([
  {
    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>
  <USelect v-model="value" :items="items" class="w-48" />
</template>

项目中带有图标

可以使用icon属性在项目中显示Icon。

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

const value = ref(items.value[0]?.value)

const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
</script>

<template>
  <USelect v-model="value" :items="items" value-key="value" :icon="icon" class="w-48" />
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { SelectItem } 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 SelectItem[])

const value = ref(items.value[0]?.value)

const icon = computed(() => items.value.find(item => item.value === value.value)?.icon)
</script>

<template>
  <USelect v-model="value" :items="items" value-key="value" :icon="icon" class="w-48" />
</template>
在本例中,图标是根据选定项的value属性计算的。
您也可以使用#leading插槽来显示选定的图标。

物品中有头像

您可以使用avatar属性在项目中显示Avatar。

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

const items = ref([
  {
    label: 'benjamincanac',
    value: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      alt: 'benjamincanac',
      loading: 'lazy' as const
    }
  },
  {
    label: 'HugoRCD',
    value: 'HugoRCD',
    avatar: {
      src: 'https://github.com/HugoRCD.png',
      alt: 'HugoRCD',
      loading: 'lazy' as const
    }
  },
  {
    label: 'atinux',
    value: 'atinux',
    avatar: {
      src: 'https://github.com/atinux.png',
      alt: 'atinux',
      loading: 'lazy' as const
    }
  },
  {
    label: 'romhml',
    value: 'romhml',
    avatar: {
      src: 'https://github.com/romhml.png',
      alt: 'romhml',
      loading: 'lazy' as const
    }
  }
] satisfies SelectItem[])

const value = ref(items.value[0]?.value)

const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
</script>

<template>
  <USelect v-model="value" :items="items" value-key="value" :avatar="avatar" class="w-48" />
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import type { SelectItem } from '@nuxt/ui'

const items = ref([
  {
    label: 'benjamincanac',
    value: 'benjamincanac',
    avatar: {
      src: 'https://github.com/benjamincanac.png',
      alt: 'benjamincanac',
      loading: 'lazy' as const
    }
  },
  {
    label: 'HugoRCD',
    value: 'HugoRCD',
    avatar: {
      src: 'https://github.com/HugoRCD.png',
      alt: 'HugoRCD',
      loading: 'lazy' as const
    }
  },
  {
    label: 'atinux',
    value: 'atinux',
    avatar: {
      src: 'https://github.com/atinux.png',
      alt: 'atinux',
      loading: 'lazy' as const
    }
  },
  {
    label: 'romhml',
    value: 'romhml',
    avatar: {
      src: 'https://github.com/romhml.png',
      alt: 'romhml',
      loading: 'lazy' as const
    }
  }
] satisfies SelectItem[])

const value = ref(items.value[0]?.value)

const avatar = computed(() => items.value.find(item => item.value === value.value)?.avatar)
</script>

<template>
  <USelect v-model="value" :items="items" value-key="value" :avatar="avatar" class="w-48" />
</template>
在这个例子中,化身是根据所选项目的value属性计算的。
您也可以使用#leading插槽来显示选定的头像。

带芯片的物品

您可以使用chip属性在项目中显示Chip。

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

const value = ref(items.value[0]?.value)

function getChip(value: string) {
  return items.value.find(item => item.value === value)?.chip
}
</script>

<template>
  <USelect v-model="value" :items="items" value-key="value" class="w-48">
    <template #leading="{ modelValue, ui }">
      <UChip
        v-if="modelValue"
        v-bind="getChip(modelValue)"
        inset
        standalone
        :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
        :class="ui.itemLeadingChip()"
      />
    </template>
  </USelect>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { SelectItem, 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 SelectItem[])

const value = ref(items.value[0]?.value)

function getChip(value: string) {
  return items.value.find(item => item.value === value)?.chip
}
</script>

<template>
  <USelect v-model="value" :items="items" value-key="value" class="w-48">
    <template #leading="{ modelValue, ui }">
      <UChip
        v-if="modelValue"
        v-bind="getChip(modelValue)"
        inset
        standalone
        :size="(ui.itemLeadingChipSize() as ChipProps['size'])"
        :class="ui.itemLeadingChip()"
      />
    </template>
  </USelect>
</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>
  <USelect v-model="value" v-model:open="open" :items="items" class="w-48" />
</template>
<script setup lang="ts">
import { ref } from 'vue'

const open = ref(false)
const items = ref(['Backlog', 'Todo', 'In Progress', 'Done'])
const value = ref('Backlog')

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

<template>
  <USelect v-model="value" v-model:open="open" :items="items" class="w-48" />
</template>
在本例中,利用defineShortcuts,您可以通过按:kbd{value="O"}来切换选择。

带旋转图标

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

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

<template>
  <USelect
    v-model="value"
    :items="items"
    :ui="{
      trailingIcon: 'group-data-[state=open]:rotate-180 transition-transform duration-200'
    }"
    class="w-48"
  />
</template>
<script setup lang="ts">
import { ref } from 'vue'

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

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

使用获取的项目

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

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

const { data: users, status, execute } = await useLazyFetch('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}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

function getUserAvatar(value: string) {
  return users.value?.find(user => user.value === value)?.avatar || {}
}

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

<template>
  <USelect
    :items="users"
    :loading="status === 'pending'"
    icon="i-lucide-user"
    placeholder="Select user"
    value-key="value"
    class="w-48"
    @update:open="onOpen"
  >
    <template #leading="{ modelValue, ui }">
      <UAvatar
        v-if="modelValue"
        v-bind="getUserAvatar(modelValue)"
        :size="(ui.leadingAvatarSize() as AvatarProps['size'])"
        :class="ui.leadingAvatar()"
      />
    </template>
  </USelect>
</template>
本例使用useLazyFetch和immediate: false,仅在菜单打开时获取数据,避免了页面加载时不必要的API调用。

无限滚动:badge{label="4.4+" class="align-text-top"}

您可以使用useInfiniteScroll组合文件在用户滚动时加载更多数据。

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

type User = {
  firstName: string
}

type UserResponse = {
  users: User[]
  total: number
  skip: number
  limit: number
}

const skip = ref(0)

const { data, status, execute } = await useLazyFetch(
  'https://dummyjson.com/users?limit=10&select=firstName',
  {
    key: 'select-users-infinite-scroll',
    params: { skip },
    transform: (data?: UserResponse) => {
      return data?.users.map((user) => user.firstName)
    },
    immediate: false
  }
)

const users = ref<string[]>([])

watch(data, () => {
  users.value = [...users.value, ...(data.value || [])]
})

function onOpen() {
  if (!users.value?.length) {
    execute()
  }
}

const select = useTemplateRef('select')

onMounted(() => {
  useInfiniteScroll(
    () => select.value?.viewportRef,
    () => {
      skip.value += 10
    },
    {
      canLoadMore: () => {
        return status.value !== 'pending'
      }
    }
  )
})
</script>

<template>
  <USelect ref="select" placeholder="Select user" :items="users" @update:open="onOpen" />
</template>
<script setup lang="ts">
import { ref, watch, onMounted, useTemplateRef } from 'vue'
import { useInfiniteScroll } from '@vueuse/core'

type User = {
  firstName: string
}

type UserResponse = {
  users: User[]
  total: number
  skip: number
  limit: number
}

const skip = ref(0)

const { data, status, execute } = await useLazyFetch(
  'https://dummyjson.com/users?limit=10&select=firstName',
  {
    key: 'select-users-infinite-scroll',
    params: { skip },
    transform: (data?: UserResponse) => {
      return data?.users.map((user) => user.firstName)
    },
    immediate: false
  }
)

const users = ref<string[]>([])

watch(data, () => {
  users.value = [...users.value, ...(data.value || [])]
})

function onOpen() {
  if (!users.value?.length) {
    execute()
  }
}

const select = useTemplateRef('select')

onMounted(() => {
  useInfiniteScroll(
    () => select.value?.viewportRef,
    () => {
      skip.value += 10
    },
    {
      canLoadMore: () => {
        return status.value !== 'pending'
      }
    }
  )
})
</script>

<template>
  <USelect ref="select" placeholder="Select user" :items="users" @update:open="onOpen" />
</template>
本例使用useLazyFetch和immediate: false,因此数据仅在用户滚动时加载。

具有完整内容宽度

您可以通过在ui.content插槽上添加min-w-fit类来将内容扩展到其项目的全宽。

<script setup lang="ts">
const value = ref<string>()

const { data: users, execute } = await useLazyFetch('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}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

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

<template>
  <USelect
    v-model="value"
    :items="users"
    placeholder="Select user"
    value-key="value"
    :ui="{ content: 'min-w-fit' }"
    class="w-48"
    @update:open="onOpen"
  >
    <template #item-label="{ item }">
      {{ item.label }}

      <span class="text-muted">
        {{ item.email }}
      </span>
    </template>
  </USelect>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const value = ref<string>()

const { data: users, execute } = await useLazyFetch('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}`, loading: 'lazy' as const }
    }))
  },
  immediate: false
})

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

<template>
  <USelect
    v-model="value"
    :items="users"
    placeholder="Select user"
    value-key="value"
    :ui="{ content: 'min-w-fit' }"
    class="w-48"
    @update:open="onOpen"
  >
    <template #item-label="{ item }">
      {{ item.label }}

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

API

Props

Prop Default Type
id
string
placeholder
string

The placeholder text when the select is empty.

color
'primary'
"primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
variant
'outline'
"outline" | "soft" | "subtle" | "ghost" | "none"
size
'md'
"sm" | "md" | "xs" | "lg" | "xl"
trailingIcon
appConfig.ui.icons.chevronDown
any

The icon displayed to open the menu.

selectedIcon
appConfig.ui.icons.check
any

The icon displayed when an item is selected.

content
{ side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
SelectContentProps & Partial<EmitsToProps<SelectContentImplEmits>>

The content of the menu.

arrow
false
boolean | SelectArrowProps

Display an arrow alongside the menu. { rounded: true }

portal
true
string | false | true | HTMLElement

Render the menu in a portal.

valueKey
'value'
VK

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

labelKey
'label'
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 label.

descriptionKey
'description'
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 description.

items
T
defaultValue
_Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod>

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

modelValue
_Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod>

The controlled value of the Select. Can be bind as v-model.

modelModifiers
Mod
multiple
M

Whether multiple options can be selected or not.

highlight
boolean

Highlight the ring color like a focus state.

fixed
boolean

Keep the mobile text size on all breakpoints.

autofocus
boolean
autofocusDelay
0
number
disabled
boolean

When true, prevents the user from interacting with Select

open
boolean

The controlled open state of the Select. Can be bind as v-model:open.

defaultOpen
boolean

The open state of the select when it is initially rendered. Use when you do not need to control its open state.

nullableValue
string

The value of the hidden native select option when the model value is nullish.

autocomplete
string

Native html input autocomplete attribute.

name
string

The name of the field. Submitted with its owning form as part of a name/value pair.

required
boolean

When true, indicates that the user must set the value before the owning form can be submitted.

icon
any

Display an icon based on the leading and trailing props.

avatar
AvatarProps

Display an avatar on the left side.

leading
boolean

When true, the icon will be displayed on the left side.

leadingIcon
any

Display an icon on the left side.

trailing
boolean

When true, the icon will be displayed on the right side.

loading
boolean

When true, the loading icon will be displayed.

loadingIcon
appConfig.ui.icons.loading
any

The icon when the loading prop is true.

ui
{ base?: SlotClass; leading?: SlotClass; leadingIcon?: SlotClass; leadingAvatar?: SlotClass; leadingAvatarSize?: SlotClass; trailing?: SlotClass; trailingIcon?: SlotClass; value?: SlotClass; placeholder?: SlotClass; arrow?: SlotClass; content?: SlotClass; viewport?: SlotClass; group?: SlotClass; empty?: SlotClass; label?: SlotClass; separator?: SlotClass; item?: SlotClass; itemLeadingIcon?: SlotClass; itemLeadingAvatar?: SlotClass; itemLeadingAvatarSize?: SlotClass; itemLeadingChip?: SlotClass; itemLeadingChipSize?: SlotClass; itemTrailing?: SlotClass; itemTrailingIcon?: SlotClass; itemWrapper?: SlotClass; itemLabel?: SlotClass; itemDescription?: SlotClass; }
此组件还支持所有原生<button> HTML属性。

Slots

Slot Type
leading
{ modelValue: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod>; open: boolean; ui: object; }
default
{ modelValue: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod>; open: boolean; ui: object; }
trailing
{ modelValue: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod>; open: boolean; ui: object; }
item
{ item: NestedItem<T>; index: number; ui: object; }
item-leading
{ item: NestedItem<T>; index: number; ui: object; }
item-label
{ item: NestedItem<T>; index: number; }
item-description
{ item: NestedItem<T>; index: number; }
item-trailing
{ item: NestedItem<T>; index: number; ui: object; }
content-top
{}
content-bottom
{}

Emits

Event Type
update:modelValue
[value: _Number<_Optional<_Nullable<GetModelValue<T, VK, M, ExcludeItem>, Mod>, Mod>, Mod>]
update:open
[value: boolean]
change
[event: Event]
blur
[event: FocusEvent]
focus
[event: FocusEvent]

曝光

通过模板引用访问组件时,可以使用以下命令:

名称类型
triggerRefRef<HTMLButtonElement | null>
viewportRefRef<HTMLDivElement | null>

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    select: {
      slots: {
        base: [
          'relative group rounded-md inline-flex items-center 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-bg stroke-default',
        content: 'max-h-[min(15rem,var(--reka-select-content-available-height,15rem))] w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden origin-(--reka-select-content-transform-origin) pointer-events-auto flex flex-col',
        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-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 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',
        itemWrapper: 'flex-1 flex flex-col min-w-0',
        itemLabel: 'truncate',
        itemDescription: 'truncate text-muted'
      },
      variants: {
        fieldGroup: {
          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-sm/4 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-2 text-xs'
          },
          sm: {
            base: 'px-2.5 py-1.5 text-sm/4 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-2.5 text-xs'
          },
          md: {
            base: 'px-2.5 py-1.5 text-base/5 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-2.5 text-sm'
          },
          lg: {
            base: 'px-3 py-2 text-base/5 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-3 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-3 text-base'
          }
        },
        variant: {
          outline: 'text-highlighted bg-default ring ring-inset ring-accented hover:bg-elevated disabled:bg-default',
          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 hover:bg-accented/75 disabled:bg-elevated',
          ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
          none: 'text-highlighted bg-transparent focus:outline-none'
        },
        color: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        leading: {
          true: ''
        },
        trailing: {
          true: ''
        },
        loading: {
          true: ''
        },
        highlight: {
          true: ''
        },
        fixed: {
          false: ''
        },
        type: {
          file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
        },
        position: {
          popper: {
            content: 'data-[state=open]:animate-[scale-in_100ms_var(--ease-out)] data-[state=closed]:animate-[scale-out_100ms_var(--ease-out)]'
          },
          'item-aligned': {
            content: ''
          }
        },
        multiple: {
          true: ''
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          variant: [
            'outline',
            'subtle'
          ],
          class: 'outline-primary/25 focus-visible:outline-3 focus-visible:ring-primary'
        },
        {
          color: 'primary',
          variant: [
            'soft',
            'ghost'
          ],
          class: 'outline-primary/25 focus-visible:outline-3'
        },
        {
          color: 'primary',
          highlight: true,
          class: 'ring ring-inset ring-primary'
        },
        {
          color: 'neutral',
          variant: [
            'outline',
            'subtle'
          ],
          class: 'outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
        },
        {
          color: 'neutral',
          variant: [
            'soft',
            'ghost'
          ],
          class: 'outline-inverted/25 focus-visible:outline-3'
        },
        {
          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'
          }
        },
        {
          fixed: false,
          size: 'xs',
          class: 'md:text-xs'
        },
        {
          fixed: false,
          size: 'sm',
          class: 'md:text-xs'
        },
        {
          fixed: false,
          size: 'md',
          class: 'md:text-sm'
        },
        {
          fixed: false,
          size: 'lg',
          class: 'md:text-sm'
        }
      ],
      defaultVariants: {
        size: 'md',
        color: 'primary',
        variant: 'outline',
        position: 'popper'
      }
    }
  }
})
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: {
        select: {
          slots: {
            base: [
              'relative group rounded-md inline-flex items-center 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-bg stroke-default',
            content: 'max-h-[min(15rem,var(--reka-select-content-available-height,15rem))] w-(--reka-select-trigger-width) bg-default shadow-lg rounded-md ring ring-default overflow-hidden origin-(--reka-select-content-transform-origin) pointer-events-auto flex flex-col',
            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-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 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',
            itemWrapper: 'flex-1 flex flex-col min-w-0',
            itemLabel: 'truncate',
            itemDescription: 'truncate text-muted'
          },
          variants: {
            fieldGroup: {
              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-sm/4 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-2 text-xs'
              },
              sm: {
                base: 'px-2.5 py-1.5 text-sm/4 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-2.5 text-xs'
              },
              md: {
                base: 'px-2.5 py-1.5 text-base/5 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-2.5 text-sm'
              },
              lg: {
                base: 'px-3 py-2 text-base/5 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-3 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-3 text-base'
              }
            },
            variant: {
              outline: 'text-highlighted bg-default ring ring-inset ring-accented hover:bg-elevated disabled:bg-default',
              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 hover:bg-accented/75 disabled:bg-elevated',
              ghost: 'text-highlighted bg-transparent hover:bg-elevated focus:bg-elevated disabled:bg-transparent dark:disabled:bg-transparent',
              none: 'text-highlighted bg-transparent focus:outline-none'
            },
            color: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            leading: {
              true: ''
            },
            trailing: {
              true: ''
            },
            loading: {
              true: ''
            },
            highlight: {
              true: ''
            },
            fixed: {
              false: ''
            },
            type: {
              file: 'file:me-1.5 file:font-medium file:text-muted file:outline-none'
            },
            position: {
              popper: {
                content: 'data-[state=open]:animate-[scale-in_100ms_var(--ease-out)] data-[state=closed]:animate-[scale-out_100ms_var(--ease-out)]'
              },
              'item-aligned': {
                content: ''
              }
            },
            multiple: {
              true: ''
            }
          },
          compoundVariants: [
            {
              color: 'primary',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'outline-primary/25 focus-visible:outline-3 focus-visible:ring-primary'
            },
            {
              color: 'primary',
              variant: [
                'soft',
                'ghost'
              ],
              class: 'outline-primary/25 focus-visible:outline-3'
            },
            {
              color: 'primary',
              highlight: true,
              class: 'ring ring-inset ring-primary'
            },
            {
              color: 'neutral',
              variant: [
                'outline',
                'subtle'
              ],
              class: 'outline-inverted/25 focus-visible:outline-3 focus-visible:ring-inverted'
            },
            {
              color: 'neutral',
              variant: [
                'soft',
                'ghost'
              ],
              class: 'outline-inverted/25 focus-visible:outline-3'
            },
            {
              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'
              }
            },
            {
              fixed: false,
              size: 'xs',
              class: 'md:text-xs'
            },
            {
              fixed: false,
              size: 'sm',
              class: 'md:text-xs'
            },
            {
              fixed: false,
              size: 'md',
              class: 'md:text-sm'
            },
            {
              fixed: false,
              size: 'lg',
              class: 'md:text-sm'
            }
          ],
          defaultVariants: {
            size: 'md',
            color: 'primary',
            variant: 'outline',
            position: 'popper'
          }
        }
      }
    })
  ]
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.

Changelog

No recent changes