组件

Select

一个 React 选择器,采用 Liquid Glass 触发器,支持单选或多选、分组选项与五种尺寸。

Select 内部负责标签、触发器、玻璃表面、当前值、箭头、Portal、玻璃浮层与选项。选项通过 items 数组传入,同一份数据同时驱动触发器文字和浮层列表;选项可以是平铺的,也可以按组传入,设置 multiple 后值会变为数组。

使用 label 与 description 提供可见字段文本。没有可见标签时,请通过 aria-label 或 aria-labelledby 为触发器提供可访问名称。设置 name 后,选中值会通过隐藏的原生输入提交。

基础示例

示例展示带标签、描述、占位文本与禁用选项的字段,并通过 defaultValue 选中第一个选项。

Fruit
Choose the fruit for the next delivery.

多选

设置 multiple 后可以选择多个选项。此时值变为数组,每次选中后浮层保持打开,列表会暴露 aria-multiselectable。当触发器需要显示摘要而不是逐项列出标签时,使用 renderValue;它会覆盖 placeholder,因此空状态文案需要由函数自行返回。

Languages
The popup stays open while you toggle options.

分组选项

在 items 中传入 { label, items } 形式的分组。每组会渲染标题,并作为带标签的分组被播报;触发器仍会从展平后的选项中解析标签。

Produce
Options are grouped by category.

对象值

Value 不限于字符串。可以把对象作为选项值,并通过 itemToStringValue 控制表单提交、通过 isItemEqualToValue 匹配引用不同但内容相等的对象。renderValue 可以在触发器中展示完整对象。

Shipping method
Object values keep the full record in state.

尺寸

支持 xs / sm / md / lg / xl,默认 md。触发器高度、内边距、文字与箭头会一起缩放。

xs
sm
md
lg
xl

受控用法

value 与 onValueChange 控制选中值。把受控 value 设为 null 可以清空选择;组件本身不渲染清除控件,因此示例在字段旁提供了独立的清除操作。

Plan
Switch plans at any time.

Selected plan: team

表单用法

设置 name 后,选中值会通过隐藏的原生输入提交。required 会参与原生表单校验,form 可将字段关联到文档其他位置的表单。

Plan
The selected value is submitted with the form.

No value submitted.

无障碍

Select 遵循 Base UI 选择器模式:触发器是 combobox,暴露 aria-haspopup="listbox"、aria-expanded 与 aria-controls;内部列表是 listbox;每个选项都是 option。ArrowDown 与 ArrowUp 在选项之间移动,typeahead 会匹配标签,Enter 选中高亮项。Escape 关闭浮层并把焦点返回触发器。

设置 multiple 后,列表会暴露 aria-multiselectable="true",每个选项暴露 aria-selected,激活选项会切换选中状态而不会关闭浮层。分组选项会渲染在由标题命名的 group 中。

可见的 label 为触发器命名,description 通过 aria-describedby 关联。没有可见标签时,请使用 aria-label 或 aria-labelledby。禁用的选项仍会被播报,但无法选中。必须选择值时请设置 required;共享表单模式见可访问性指南。

API 参考

Select

属性类型默认值说明
itemsreadonly (SelectItemProps | SelectItemGroupProps)[]—选择器中的选项,可按组传入。必填。
labelReactNode—与触发器关联的可见标签。
descriptionReactNode—触发器下方的辅助说明,通过 aria-describedby 关联。
placeholderReactNode—未选择时显示的文字。
renderValue(value) => ReactNode—格式化触发器中的当前值。参数为 Value | null,多选时为 readonly Value[]。会覆盖 placeholder。
multiplebooleanfalse允许选择多个选项;此时 value、defaultValue 与 onValueChange 使用数组。
valueValue | null—受控选中值。多选时使用 readonly Value[] | null。
defaultValueValue | null—非受控时的初始值。多选时使用 readonly Value[] | null。
onValueChange(value, details) => void—选中值变化时调用。单选接收 Value | null,多选接收 Value[]。
openboolean—受控的浮层显示状态。
defaultOpenbooleanfalse非受控时的初始浮层状态。
onOpenChange(open: boolean, details) => void—浮层打开或关闭时调用。
onOpenChangeComplete(open: boolean) => void—打开或关闭动画结束后调用。
modalbooleantrue浮层打开时锁定外部交互。
readOnlybooleanfalse禁止修改当前值。
disabledbooleanfalse禁用触发器与选项。
highlightItemOnHoverbooleantrue指针移动时高亮选项。设为 false 后可单独为 :hover 设置样式,与 data-highlighted 区分。
itemToStringLabel(itemValue: Value) => string—将对象值转换为触发器中显示的文本。
itemToStringValue(itemValue: Value) => string—将对象值转换为表单提交的字符串。
isItemEqualToValue(itemValue: Value, value: Value) => booleanObject.is自定义相等判断,用于匹配引用不同但内容相等的对象值。
namestring—隐藏输入框的表单字段名。多选时每个选中值提交一个输入。
formstring—隐藏输入框所属的表单。
autoCompletestring—传给隐藏输入框的自动填充提示。
requiredbooleanfalse表单提交前必须选择值。
idstring—选择器各部分的基础 id。
actionsRefRefObject<Select.Root.Actions | null>—命令式的 close 与 unmount 操作。
inputRefRef<HTMLInputElement>—指向隐藏输入框的 ref。
aria-labelstring—没有可见标签时触发器的可访问名称。
aria-labelledbystring—从其他元素为触发器命名。
aria-describedbystring—应用于触发器的额外描述 ID。
size"xs" | "sm" | "md" | "lg" | "xl""md"控制触发器高度、内边距、文字与图标尺寸。
side"top" | "bottom" | "left" | "right" | "inline-start" | "inline-end""bottom"首选方位。
align"start" | "center" | "end""center"相对触发器的对齐方式。
sideOffsetnumber | OffsetFunction6触发器与浮层的像素距离。
alignOffsetnumber | OffsetFunction0沿对齐轴的像素偏移。
collisionPaddingPadding每边 5px浮层与碰撞边界之间的留白。
alignItemWithTriggerbooleanfalse让浮层与触发器重叠,使选中项与触发器文字对齐。
classNamestring—合并到字段根元素的 Tailwind 类名。
styleCSSProperties—内联样式,合并到与 className 相同的元素。
ui{ root?: ClassValue; label?: ClassValue; trigger?: ClassValue; glass?: ClassValue; overlay?: ClassValue; value?: ClassValue; icon?: ClassValue; description?: ClassValue; positioner?: ClassValue; popup?: ClassValue; popupGlass?: ClassValue; popupOverlay?: ClassValue; list?: ClassValue; group?: ClassValue; groupLabel?: ClassValue; item?: ClassValue; itemIndicator?: ClassValue; itemText?: ClassValue }—按 data-slot 组织的内部槽位类名。

SelectItemProps

属性类型默认值说明
valueany—提交并传给 onValueChange 的值。支持任意类型。必填。
labelReactNode—选项与触发器中的可见内容。必填。
textValuestring—键盘 typeahead 使用的纯文本标签;字符串标签会自动使用。
disabledbooleanfalse禁用该选项。

SelectItemGroupProps

属性类型默认值说明
labelReactNode—渲染在分组上方的可见标题。必填。
itemsreadonly SelectItemProps[]—分组中的选项。必填。

ui 的键对应下方列出的 data-slot 值。其余 Base UI Select.Root 属性都会原样透传。

属性说明
data-open选择器打开时存在于浮层上。
data-closed浮层关闭或正在关闭时存在。
data-placeholder未选择任何选项时存在于当前值上。
data-selected选中项及其指示器上存在。
data-highlighted键盘或指针高亮该选项时存在。
data-disabled选择器或选项禁用时存在。
data-readonly选择器只读时存在。
data-popup-open浮层打开时存在于触发器上。
data-side浮层的实际方位。
data-align实际对齐方式(start、center 或 end)。
data-starting-style浮层开始进入动画时存在。
data-ending-style浮层正在退出动画时存在。
aria-multiselectable设置 multiple 时,列表上为 true。
data-slot标记内部结构(root、label、trigger、glass、overlay、value、icon、description、positioner、popup、popup-glass、popup-overlay、list、group、group-label、item、item-indicator、item-text)。

主题

组件使用共享玻璃材质。可以在父级调整 --ui-glass-* token,用 className 控制布局,并通过 ui 按 data-slot 调整内部槽位。组件级数值位于 src/theme/select.ts。Token 分层与预设见主题指南。

相关组件

  • Input — 与选择器并排使用的自由文本字段。
  • Menu — 执行操作,而不是维护一个持续选中的值。
  • Radio Group — 需要始终显示全部选项时。