跳至内容

选择

显示一个选项列表,供用户通过按钮触发选择。
vue
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref } from 'vue'
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectItemText,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectScrollDownButton,
  SelectScrollUpButton,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
  SelectViewport,
} from 'radix-vue'

const fruit = ref()

const options = ['Apple', 'Banana', 'Blueberry', 'Grapes', 'Pineapple']
const vegetables = ['Aubergine', 'Broccoli', 'Carrot', 'Courgette', 'Leek']
</script>

<template>
  <SelectRoot v-model="fruit">
    <SelectTrigger
      class="inline-flex min-w-[160px] items-center justify-between rounded px-[15px] text-[13px] leading-none h-[35px] gap-[5px] bg-white text-grass11 shadow-[0_2px_10px] shadow-black/10 hover:bg-mauve3 focus:shadow-[0_0_0_2px] focus:shadow-black data-[placeholder]:text-green9 outline-none"
      aria-label="Customise options"
    >
      <SelectValue placeholder="Select a fruit..." />
      <Icon
        icon="radix-icons:chevron-down"
        class="h-3.5 w-3.5"
      />
    </SelectTrigger>

    <SelectPortal>
      <SelectContent
        class="min-w-[160px] bg-white rounded shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] will-change-[opacity,transform] data-[side=top]:animate-slideDownAndFade data-[side=right]:animate-slideLeftAndFade data-[side=bottom]:animate-slideUpAndFade data-[side=left]:animate-slideRightAndFade z-[100]"
        :side-offset="5"
      >
        <SelectScrollUpButton class="flex items-center justify-center h-[25px] bg-white text-violet11 cursor-default">
          <Icon icon="radix-icons:chevron-up" />
        </SelectScrollUpButton>

        <SelectViewport class="p-[5px]">
          <SelectLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
            Fruits
          </SelectLabel>
          <SelectGroup>
            <SelectItem
              v-for="(option, index) in options"
              :key="index"
              class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] pr-[35px] pl-[25px] relative select-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              :value="option"
            >
              <SelectItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
                <Icon icon="radix-icons:check" />
              </SelectItemIndicator>
              <SelectItemText>
                {{ option }}
              </SelectItemText>
            </SelectItem>
          </SelectGroup>
          <SelectSeparator class="h-[1px] bg-green6 m-[5px]" />
          <SelectLabel class="px-[25px] text-xs leading-[25px] text-mauve11">
            Vegetables
          </SelectLabel>
          <SelectGroup>
            <SelectItem
              v-for="(option, index) in vegetables"
              :key="index"
              class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] pr-[35px] pl-[25px] relative select-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
              :value="option"
              :disabled="option === 'Courgette'"
            >
              <SelectItemIndicator class="absolute left-0 w-[25px] inline-flex items-center justify-center">
                <Icon icon="radix-icons:check" />
              </SelectItemIndicator>
              <SelectItemText>
                {{ option }}
              </SelectItemText>
            </SelectItem>
          </SelectGroup>
        </SelectViewport>

        <SelectScrollDownButton class="flex items-center justify-center h-[25px] bg-white text-violet11 cursor-default">
          <Icon icon="radix-icons:chevron-down" />
        </SelectScrollDownButton>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

功能

  • 可以被控制或不受控制。
  • 提供2种定位模式。
  • 支持项目、标签、项目组。
  • 焦点完全管理。
  • 完整的键盘导航。
  • 支持自定义占位符。
  • 支持键入提示。
  • 支持从右到左方向。

安装

从命令行安装组件。

sh
$ npm add radix-vue

解剖结构

导入所有部分并将其拼凑在一起。

vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectScrollDownButton,
  SelectScrollUpButton,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
  SelectViewport,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger>
      <SelectValue />
      <SelectIcon />
    </SelectTrigger>

    <SelectPortal>
      <SelectContent>
        <SelectScrollUpButton />
        <SelectViewport>
          <SelectItem>
            <SelectItemText />
            <SelectItemIndicator />
          </SelectItem>
          <SelectGroup>
            <SelectLabel />
            <SelectItem>
              <SelectItemText />
              <SelectItemIndicator />
            </SelectItem>
          </SelectGroup>
          <SelectSeparator />
        </SelectViewport>
        <SelectScrollDownButton />
        <SelectArrow />
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

API 参考

包含 Select 的所有部分

属性默认类型
autocomplete
string

原生 html 输入 autocomplete 属性。

defaultOpen
boolean

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

defaultValue
''
string

Select 初始渲染时的值。当您不需要控制 Select 的状态时使用。

dir
'ltr' | 'rtl'

组合框的阅读方向,适用时。
如果省略,则从 ConfigProvider 全局继承或假设 LTR(从左到右)阅读模式。

disabled
boolean

当为 true 时,会阻止用户与 Select 交互。

modelValue
string

Select 的受控值。可以绑定为 v-model

name
string

Select 的名称。作为名称/值对的一部分,与所属表单一起提交。

open
boolean

Select 的受控打开状态。可以绑定为 v-model:open

required
boolean

当为 true 时,表示用户必须在所属表单提交之前选择一个值。

发出有效载荷
update:modelValue
[value: string]

当值更改时调用的事件处理程序。

update:open
[value: boolean]

上下文菜单打开状态更改时调用的事件处理程序。

插槽 (默认)有效载荷
modelValue
string

当前输入值

open
boolean

当前打开状态

触发器

用于切换 Select 的按钮。SelectContent 会通过与触发器对齐来定位自身。

属性默认类型
as
'button'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

disabled
boolean
数据属性
[data-state]"open" | "closed"
[data-disabled]在禁用时出现
[data-placeholder]在有占位符时出现

反映所选值的部件。默认情况下,将呈现所选项目的文本。如果您需要更多控制,则可以控制 select 并传递自己的 children。不应对其进行样式化,以确保正确的定位。当 select 没有值时,还提供了一个可选的 placeholder 属性。

属性默认类型
as
'span'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

placeholder
''
string

当未设置 valuedefaultValue 时,将在 SelectValue 中呈现的内容。

图标

通常显示在值旁边的小图标,作为可以打开的视觉辅助。默认情况下呈现 ▼,但您可以通过 asChild 使用自己的图标,或使用 children

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

disabled
boolean

当为 true 时,会阻止用户与项目交互。

textValue
string

用于键入提示的可选文本。

默认情况下,键入提示行为将使用 SelectItemText 部分的 .textContent

当内容很复杂或在内部包含非文本内容时使用此选项。

value*
string

name 一起提交时作为数据给出的值。

传送门

使用时,会将内容部分传送至 body

属性默认类型
disabled
boolean

禁用传送并内联渲染组件

reference

forceMount
boolean

用于在需要更多控制时强制安装。当使用 Vue 动画库控制动画时很有用。

to
string | HTMLElement

Vue 原生传送组件属性 :to

reference

内容

Select 打开时弹出的组件。

属性默认类型
align
'start' | 'center' | 'end'

相对于触发器的首选对齐方式。在发生冲突时可能会更改。

alignOffset
number

相对于 startend 对齐选项的像素偏移量。

arrowPadding
number

箭头和内容边缘之间的填充。如果您的内容具有边框半径,这将防止它溢出角。

as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

avoidCollisions
boolean

当为 true 时,会覆盖侧边和对齐首选项,以防止与边界边缘发生冲突。

bodyLock
boolean

document.body 将被锁定,滚动将被禁用。

collisionBoundary
Element | (Element | null)[] | null

用作碰撞边界的元素。默认情况下,这是视窗,但您可以提供要包含在此检查中的其他元素。

collisionPadding
number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>

从边界边缘到应发生碰撞检测的位置的像素距离。接受一个数字(对所有边相同),或一个部分填充对象,例如:{ top: 20, left: 20 }。

forceMount
boolean

用于在需要更多控制时强制安装。当使用 Vue 动画库控制动画时很有用。

hideWhenDetached
boolean

当触发器被完全遮挡时是否隐藏内容。

position
'popper' | 'item-aligned'

要使用的定位模式

item-aligned (默认) - 行为类似于原生 MacOS 菜单,通过相对于活动项目定位内容。
popper - 以与我们其他基元(例如 PopoverDropdownMenu)相同的方式定位内容。

prioritizePosition
boolean

强制内容在视窗内定位。

可能会与参考元素重叠,这可能不是您想要的。

side
'top' | 'right' | 'bottom' | 'left'

打开时呈现的触发器的首选侧边。当发生冲突且 avoidCollisions 启用时将被反转。

sideOffset
number

距触发器的像素距离。

sticky
'partial' | 'always'

对齐轴上的粘性行为。partial 将使内容保持在边界内,只要触发器至少部分位于边界内,而 "always" 将使内容始终保持在边界内。

updatePositionStrategy
'always' | 'optimized'

在每帧动画中更新浮动元素位置的策略。

发出有效载荷
closeAutoFocus
[event: Event]

关闭时自动聚焦时调用的事件处理程序。可以阻止。

escapeKeyDown
[event: KeyboardEvent]

按下 Escape 键时调用的事件处理程序。可以阻止。

pointerDownOutside
[event: PointerDownOutsideEvent]

DismissableLayer 外部发生 pointerdown 事件时调用的事件处理程序。可以阻止。

数据属性
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS 变量描述
--radix-select-content-transform-origin
从内容和箭头位置/偏移量计算的 transform-origin。仅在 position="popper" 时出现。
--radix-select-content-available-width
触发器和边界边缘之间的剩余宽度。仅当 position="popper" 时存在。
--radix-select-content-available-height
触发器和边界边缘之间的剩余高度。仅当 position="popper" 时存在。
--radix-select-trigger-width
触发器的宽度。仅当 position="popper" 时存在。
--radix-select-trigger-height
触发器的高度。仅当 position="popper" 时存在。

视窗

包含所有项目的滚动视窗。

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

nonce
string

将添加 nonce 属性到 style 标签,该属性可用于内容安全策略。
如果省略,则从 ConfigProvider 全局继承。

项目

包含选择项目的组件。

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

disabled
boolean

当为 true 时,会阻止用户与项目交互。

textValue
string

用于键入提示的可选文本。

默认情况下,键入提示行为将使用 SelectItemText 部分的 .textContent

当内容很复杂或在内部包含非文本内容时使用此选项。

value*
string

name 一起提交时作为数据给出的值。

数据属性
[data-state]"checked" | "unchecked"
[data-highlighted]高亮显示时出现
[data-disabled]在禁用时出现

项目文本

项目的文本部分。它应该只包含您希望在选择该项目时在触发器中看到的内容。它不应该被样式化以确保正确的定位。

属性默认类型
as
'span'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

项目指示器

当项目被选中时呈现。您可以直接对该元素进行样式化,也可以将其用作包装器以将图标放入其中,或者两者都做。

属性默认类型
as
'span'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

向上滚动按钮

一个可选按钮,用作显示视窗溢出以及功能上启用向上滚动的便利工具。

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

向下滚动按钮

一个可选按钮,用作显示视窗溢出以及功能上启用向下滚动的便利工具。

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

分组

用于对多个项目进行分组。与 SelectLabel 结合使用,以确保通过自动标记提供良好的可访问性。

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

标签

用于呈现分组的标签。它不会使用箭头键可聚焦。

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

for
string

分隔符

用于在 Select 中直观地分隔项目

属性默认类型
as
'div'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

箭头

一个可选箭头元素,与内容一起呈现。这可以用来帮助直观地将触发器与 SelectContent 链接起来。必须在 SelectContent 内呈现。仅当 position 设置为 popper 时可用。

属性默认类型
as
'svg'
AsTag | 组件

此组件应呈现为的元素或组件。可以被 asChild 覆盖

asChild
boolean

将默认呈现的元素更改为作为子元素传递的元素,合并它们的属性和行为。

阅读我们的 组合 指南以了解更多详情。

高度
5
number

箭头的像素高度。

宽度
10
number

箭头的像素宽度。

示例

更改定位模式

默认情况下,Select 的行为类似于本机 MacOS 菜单,将 SelectContent 相对于活动项目进行定位。如果您希望采用类似于 PopoverDropdownMenu 的替代定位方法,那么您可以将 position 设置为 popper 并使用其他对齐选项,例如 sidesideOffset 等。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent
        position="popper"
        :side-offset="5"
      >

      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

约束内容大小

SelectContent 上使用 position="popper" 时,您可能希望约束内容的宽度以使其与触发器宽度匹配。您可能还希望约束其高度,使其不超过视窗。

我们公开了几个 CSS 自定义属性,例如 --radix-select-trigger-width--radix-select-content-available-height 来支持这一点。使用它们来约束内容尺寸。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent
        class="SelectContent"
        position="popper"
        :side-offset="5"
      >

      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.SelectContent {
  width: var(--radix-select-trigger-width);
  max-height: var(--radix-select-content-available-height);
}

包含禁用项目

您可以通过 data-disabled 属性向禁用项目添加特殊样式。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem
            class="SelectItem"
            disabled
          >

          </SelectItem>
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.SelectItem[data-disabled] {
  color: "gainsboro";
}

包含占位符

您可以在 Value 上使用 placeholder 道具,用于选择没有值时。Trigger 上还有一个 data-placeholder 属性,可以帮助您进行样式设置。

vue
// index.vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
import './styles.css'
</script>

<template>
  <SelectRoot>
    <SelectTrigger class="SelectTrigger">
      <SelectValue placeholder="Pick an option" />
      <SelectIcon />
    </SelectTrigger>
    <SelectPortal>
      <SelectContent></SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.SelectTrigger[data-placeholder] {
  color: "gainsboro";
}

包含分隔符

使用 Separator 部分在项目之间添加分隔符。

vue
<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
          <SelectSeparator />
          <SelectItem></SelectItem>
          <SelectItem></SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

包含分组项目

使用 GroupLabel 部分将项目分组到一个部分中。

vue
<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectGroup>
            <SelectLabel>Label</SelectLabel>
            <SelectItem></SelectItem>
            <SelectItem></SelectItem>
            <SelectItem></SelectItem>
          </SelectGroup>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

包含复杂项目

您可以在项目中使用自定义内容。

vue
<script setup lang="ts">
import {
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem>
            <SelectItemText>
              <img src="">
              Adolfo Hess
            </SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
          <SelectItem></SelectItem> <SelectItem></SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

控制触发器中显示的值

默认情况下,触发器将自动显示选定项目 ItemText 的内容。您可以选择将内容放在 ItemText 部分内部或外部来控制显示的内容。

如果您需要更多灵活性,可以使用 v-model 道具和将 slot 传递给 SelectValue 来控制组件。请记住确保您放入的内容是可访问的。

vue
<script setup>
const countries = { 'france': '🇫🇷', 'united-kingdom': '🇬🇧', 'spain': '🇪🇸' }

const value = ref('france')
</script>

<template>
  <SelectRoot v-model="value">
    <SelectTrigger>
      <SelectValue aria-label="value">
        {{ countries[value] }}
      </SelectValue>
      <SelectIcon />
    </SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <SelectViewport>
          <SelectItem value="france">
            <SelectItemText>France</SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
          <SelectItem value="united-kingdom">
            <SelectItemText>United Kingdom</SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
          <SelectItem value="spain">
            <SelectItemText>Spain</SelectItemText>
            <SelectItemIndicator></SelectItemIndicator>
          </SelectItem>
        </SelectViewport>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

包含自定义滚动条

默认情况下,本机滚动条被隐藏,因为我们建议您使用 ScrollUpButtonScrollDownButton 部分来获得最佳用户体验。如果您不想使用这些部分,请将您的选择与我们的 滚动区域 原语组合使用。

vue
// index.vue
<script setup lang="ts">
import {
  ScrollAreaRoot,
  ScrollAreaScrollbar,
  ScrollAreaThumb,
  ScrollAreaViewport,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <SelectRoot>
    <SelectTrigger></SelectTrigger>
    <SelectPortal>
      <SelectContent>
        <ScrollAreaRoot
          class="ScrollAreaRoot"
          type="auto"
        >
          <SelectViewport as-child>
            <ScrollAreaViewport class="ScrollAreaViewport">
              <StyledItem></StyledItem> <StyledItem></StyledItem>
              <StyledItem></StyledItem>
            </ScrollAreaViewport>
          </SelectViewport>
          <ScrollAreaScrollbar
            class="ScrollAreaScrollbar"
            orientation="vertical"
          >
            <ScrollAreaThumb class="ScrollAreaThumb" />
          </ScrollAreaScrollbar>
        </ScrollAreaRoot>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
css
/* styles.css */
.ScrollAreaRoot {
  width: 100%;
  height: 100%;
}

.ScrollAreaViewport {
  width: 100%;
  height: 100%;
}

.ScrollAreaScrollbar {
  width: 4px;
  padding: 5px 2px;
}

.ScrollAreaThumb {
  background: rgba(0, 0, 0, 0.3);
  borderradius: 3px;
}

可访问性

符合 ListBox WAI-ARIA 设计模式

有关更多信息,请参阅 W3C 仅选择组合框 示例。

键盘交互

描述
空格
SelectTrigger 处于焦点时,打开选择并聚焦选定项目。
当一个项目处于焦点时,选择该项目。
回车
SelectTrigger 处于焦点时,打开选择并聚焦第一个项目。
当一个项目处于焦点时,选择该项目。
向下箭头
SelectTrigger 处于焦点时,打开 Select
当一个项目处于焦点时,将焦点移动到下一个项目。
向上箭头
SelectTrigger 处于焦点时,打开 Select
当一个项目处于焦点时,将焦点移动到上一个项目。
Esc
关闭选择并将焦点移动到 SelectTrigger

标记

使用我们的 标签 组件,以便为 Select 提供视觉和可访问的标签

vue
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref } from 'vue'
import {
  Label,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectItemIndicator,
  SelectLabel,
  SelectPortal,
  SelectRoot,
  SelectSeparator,
  SelectTrigger,
} from 'radix-vue'
</script>

<template>
  <Label>
    Country
    <SelectRoot></SelectRoot>
  </Label>

  <!-- or -->

  <Label for="country">Country</Label>
  <SelectRoot>
    <SelectTrigger id="country">

    </SelectTrigger>
    <SelectPortal>
      <SelectContent></SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>

自定义 API

通过将基本部分抽象到您自己的组件中来创建您自己的 API。

抽象到 SelectSelectItem

此示例抽象了大部分部分。

用法

vue
<script setup lang="ts">
import { Select, SelectItem } from './your-select'
</script>

<template>
  <Select default-value="2">
    <SelectItem value="1">
      Item 1
    </SelectItem>
    <SelectItem value="2">
      Item 2
    </SelectItem>
    <SelectItem value="3">
      Item 3
    </SelectItem>
  </Select>
</template>

实现

ts
// your-select.ts
export { default as Select } from 'Select.vue'
export { default as SelectItem } from 'SelectItem.vue'
vue
<!-- Select.vue -->
<script setup lang="ts">
import { CheckIcon, ChevronDownIcon, ChevronUpIcon, } from '@radix-icons/vue'
import { SelectContent, SelectIcon, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue, SelectViewport, useForwardPropsEmits } from 'radix-vue'
import type { SelectRootEmits, SelectRootProps } from 'radix-vue'

const props = defineProps<SelectRootProps>()
const emits = defineEmits<SelectRootEmits>()

const forward = useForwardPropsEmits(props, emits)
</script>

<template>
  <SelectRoot v-bind="forward">
    <SelectTrigger>
      <SelectValue />
      <SelectIcon>
        <ChevronDownIcon />
      </SelectIcon>
    </SelectTrigger>

    <SelectPortal>
      <SelectContent>
        <SelectScrollUpButton>
          <ChevronUpIcon />
        </SelectScrollUpButton>
        <SelectViewport>
          <slot />
        </SelectViewport>
        <SelectScrollDownButton>
          <ChevronDownIcon />
        </SelectScrollDownButton>
      </SelectContent>
    </SelectPortal>
  </SelectRoot>
</template>
vue
<!-- SelectItem.vue -->
<script setup lang="ts">
import { CheckIcon } from '@radix-icons/vue'
import { SelectItem, SelectItemIndicator, type SelectItemProps, SelectItemText } from 'radix-vue'

const props = defineProps<SelectItemProps>()
</script>

<template>
  <SelectItem v-bind="props">
    <SelectItemText>
      <slot />
    </SelectItemText>
    <SelectItemIndicator>
      <CheckIcon />
    </SelectItemIndicator>
  </SelectItem>
</template>