跳到正文
GitHub

表单

Select

从一个列表里选一项,从头到尾都由我们绘制。

什么时候用它

大约十几个选项以内。再多就该用 Combobox——一个没法筛的列表,扫起来比能打字筛的更慢。

示例

default

The list is ours, not the platform’s — open it.

说明

从一个列表里选一项,从上到下都是自己的样式。

选项列表是我们自己的——用的是和别处同一套 token,所以它不会一打开就换掉字体、间距和选中色。这正是它取代原生控件成为默认值的全部理由:一个最常用的表单控件一被点击就不再属于这套系统的设计系统,那不是设计系统,那是一份只管闭合状态的样式表。

键盘约定是 Radix 的,也就是平台的:首字母跳转能用,方向键能走,Home 和 End 到两端,Escape 不选中直接关闭。那本来是留在原生方案上唯一真正站得住的论据,现在它被回答了。

超过大约十几个选项就换 Combobox——一个没法筛的列表,比一个能打字进去的更难用。在平台选择器确实更好的地方——手机上,或者一个必须在没有 JavaScript 时也能活的表单——换 NativeSelect

属性

Select props
属性类型默认值说明
children必填ReactNode若干 `SelectItem`,也可以用带 `SelectLabel` 的 `SelectGroup` 包起来。
label必填string给控件命名。必填——触发器上显示的是值,而值不是名字。
classNamestring
contentClassNamestring给选项**面板**用的类名,不是给触发器的。 `className` 设的是触发器,那是常见情况。这个是给不常见的那种:一个放在有边界的表面里的 select——默认 18rem 的列表会盖住读者正要为之做选择的那个东西,比如年份选择器盖住它自己的日历。
disabledboolean
invalidboolean把静止态的边框画成 `--danger`,并反映到 `aria-invalid` 上。
placeholderstring'Select…'

同时接受 ComponentProps<typeof SelectPrimitive.Root> 里的全部属性,它们会直接透传给底层元素,不再逐条列出。

组成部分

Composed at the call site rather than configured through props, so a layout this component did not anticipate is still expressible.

SelectItem

一个选项。对勾标出选中的那个;填充标出高亮的那个。

同时接受 ComponentProps<typeof SelectPrimitive.Item> 里的全部属性,它们会直接透传给底层元素,不再逐条列出。

SelectLabel

一组选项的等宽小标题。

必须放在 SelectGroup 里面——否则 Radix 会抛错,因为一个不属于任何分组的标题是在给虚无做标题,而辅助技术会把它当成一个选项念出来。

这个组件没有自己的属性。

SelectSeparator

分组之间的细线分隔。

这个组件没有自己的属性。

再导出

SelectRoot = SelectPrimitive.Root

Radix Select 的根节点、分组和标签,带类型的原样透传。

SelectGroup = SelectPrimitive.Group

键盘操作

Select keyboard interactions
按键作用
EnterSpace展开列表。
在选项之间移动。
a–z首字母跳转——跳到下一个以该字母开头的选项。
HomeEnd跳到第一个或最后一个选项。
Escape不选中直接关闭。

无障碍

  • 在有边界的框里——设备预览、内嵌控制台——用 `<OverlayContainer container={el}>` 包住这棵子树。面板会渲染进那个元素,按它的边界翻转,而不是按视口;框上设的 `dir` 和 `data-density` 也就跟着生效了。
  • 选项列表是我们自己的,所以它不会在打开的一瞬间换掉字体、间距和选中色——那正是原生 select 会做的事。
  • 键盘行为仍是平台的那一套:首字母跳转、方向键、Home 和 End、Escape 关闭且不选。
  • label 必填。触发器上显示的是值,值不是名字。