组件

选择

显示一个选项列表供用户选择,通过按钮触发。

import * as React from "react";
import { Select } from "radix-ui";
import classnames from "classnames";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon, } from "@radix-ui/react-icons";
import "./styles.css";
const SelectDemo = () => (
<Select.Root>
<Select.Trigger className="SelectTrigger" aria-label="Food">
<Select.Value placeholder="Select a fruit…" />
<Select.Icon className="SelectIcon">
<ChevronDownIcon />
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Content className="SelectContent">
<Select.ScrollUpButton className="SelectScrollButton">
<ChevronUpIcon />
</Select.ScrollUpButton>
<Select.Viewport className="SelectViewport">
<Select.Group>
<Select.Label className="SelectLabel">Fruits</Select.Label>
<SelectItem value="apple">Apple</SelectItem>
<SelectItem value="banana">Banana</SelectItem>
<SelectItem value="blueberry">Blueberry</SelectItem>
<SelectItem value="grapes">Grapes</SelectItem>
<SelectItem value="pineapple">Pineapple</SelectItem>
</Select.Group>
<Select.Separator className="SelectSeparator" />
<Select.Group>
<Select.Label className="SelectLabel">Vegetables</Select.Label>
<SelectItem value="aubergine">Aubergine</SelectItem>
<SelectItem value="broccoli">Broccoli</SelectItem>
<SelectItem value="carrot" disabled>
Carrot
</SelectItem>
<SelectItem value="courgette">Courgette</SelectItem>
<SelectItem value="leek">Leek</SelectItem>
</Select.Group>
<Select.Separator className="SelectSeparator" />
<Select.Group>
<Select.Label className="SelectLabel">Meat</Select.Label>
<SelectItem value="beef">Beef</SelectItem>
<SelectItem value="chicken">Chicken</SelectItem>
<SelectItem value="lamb">Lamb</SelectItem>
<SelectItem value="pork">Pork</SelectItem>
</Select.Group>
</Select.Viewport>
<Select.ScrollDownButton className="SelectScrollButton">
<ChevronDownIcon />
</Select.ScrollDownButton>
</Select.Content>
</Select.Portal>
</Select.Root>
);
const SelectItem = React.forwardRef(
({ children, className, ...props }, forwardedRef) => {
return (
<Select.Item className={classnames("SelectItem", className)} {...props} ref={forwardedRef} >
<Select.ItemText>{children}</Select.ItemText>
<Select.ItemIndicator className="SelectItemIndicator">
<CheckIcon />
</Select.ItemIndicator>
</Select.Item>
);
},
);
export default SelectDemo;

特性

    可以是受控的或非受控的。

    提供 2 种定位模式。

    支持项目、标签、项目组。

    焦点完全受管理。

    完整的键盘导航。

    支持自定义占位符。

    支持自动补全。

    支持从右到左的方向。

安装

从命令行安装组件。

npm install @radix-ui/react-select

解剖结构

导入所有部分并将它们组合在一起。

import { Select } from "radix-ui";
export default () => (
<Select.Root>
<Select.Trigger>
<Select.Value />
<Select.Icon />
</Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.ScrollUpButton />
<Select.Viewport>
<Select.Item>
<Select.ItemText />
<Select.ItemIndicator />
</Select.Item>
<Select.Group>
<Select.Label />
<Select.Item>
<Select.ItemText />
<Select.ItemIndicator />
</Select.Item>
</Select.Group>
<Select.Separator />
</Select.Viewport>
<Select.ScrollDownButton />
<Select.Arrow />
</Select.Content>
</Select.Portal>
</Select.Root>
);

API 参考

根组件

包含选择组件的所有部分。

属性类型默认值
defaultValue
string
无默认值
value
string
无默认值
onValueChange
function
无默认值
defaultOpen
boolean
无默认值
open
boolean
无默认值
onOpenChange
function
无默认值
dir
enum
无默认值
name
string
无默认值
disabled
boolean
无默认值
required
boolean
无默认值

Trigger

切换选择组件的按钮。Select.Content 将通过与触发器对齐来定位自身。

属性类型默认值
asChild
boolean
false
Data attribute
[data-state]"open" |"关闭"
[data-disabled]

禁用时显示

[data-placeholder]

有占位符时显示

Value

反映所选值的部分。默认情况下,将渲染所选项的文本。如果需要更多控制,您可以改为控制选择组件并传递您自己的 children。为了确保正确定位,不应设置样式。当选择组件没有值时,还可以使用可选的 placeholder 属性。

属性类型默认值
asChild
boolean
false
placeholder
ReactNode
无默认值

Icon

一个小图标,通常显示在值旁边,作为视觉提示,表明它可以打开。默认情况下渲染 ▼,但您可以使用 asChild 或 children 来使用您自己的图标。

属性类型默认值
asChild
boolean
false

Portal

使用时,将内容部分传送到 body 中。

属性类型默认值
container
HTMLElement
document.body

Content

选择组件打开时弹出的组件。

属性类型默认值
asChild
boolean
false
onCloseAutoFocus
function
无默认值
onEscapeKeyDown
function
无默认值
onPointerDownOutside
function
无默认值
position
enum
"item-aligned"
side
enum
"bottom"
sideOffset
number
0
align
enum
"start"
alignOffset
number
0
avoidCollisions
boolean
true
collisionBoundary
Boundary
[]
collisionPadding
number | Padding
10
arrowPadding
number
0
sticky
enum
"partial"
hideWhenDetached
boolean
false
Data attribute
[data-state]"open" |"关闭"
[data-side]"left" |"right" |"bottom" |"top"
[data-align]"start" |"end" |"center"
CSS 变量描述
--radix-select-content-transform-originThe transform-origin computed from the content and arrow positions/offsets. Only present when position="popper".
--radix-select-content-available-widthThe remaining width between the trigger and the boundary edge. Only present when position="popper".
--radix-select-content-available-heightThe remaining height between the trigger and the boundary edge. Only present when position="popper".
--radix-select-trigger-widthThe width of the trigger. Only present when position="popper".
--radix-select-trigger-heightThe height of the trigger. Only present when position="popper".

视口

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

属性类型默认值
asChild
boolean
false

项目

包含选择项目的组件。

属性类型默认值
asChild
boolean
false
value*
string
无默认值
disabled
boolean
无默认值
textValue
string
无默认值
Data attribute
[data-state]"checked" |"unchecked"
[data-highlighted]

高亮显示时显示

[data-disabled]

禁用时显示

ItemText

项目的文本部分。它应该只包含您希望在该项目被选中时在触发器中看到的文本。为了确保正确定位,不应设置样式。

属性类型默认值
asChild
boolean
false

ItemIndicator

在项目被选中时渲染。您可以直接设置此元素的样式,或者将其用作包装器来放置图标,或者两者都使用。

属性类型默认值
asChild
boolean
false

ScrollUpButton

一个可选按钮,用作显示视口溢出的提示,并实现向上滚动的功能。

属性类型默认值
asChild
boolean
false

ScrollDownButton

一个可选按钮,用作显示视口溢出的提示,并实现向下滚动的功能。

属性类型默认值
asChild
boolean
false

用于将多个项目分组。与 Select.Label 结合使用以确保通过自动标记实现良好的可访问性。

属性类型默认值
asChild
boolean
false

Label

用于渲染组的标签。它不能使用箭头键聚焦。

属性类型默认值
asChild
boolean
false

Separator

用于在选择组件中视觉上分隔项目。

属性类型默认值
asChild
boolean
false

Arrow

一个可选的箭头元素,用于与内容一起渲染。这可以帮助在视觉上将触发器与 Select.Content 链接起来。必须在 Select.Content 内部渲染。仅当 position 设置为 popper 时可用。

属性类型默认值
asChild
boolean
false
width
number
10
height
number
5

示例

更改定位模式

默认情况下,Select 的行为类似于原生的 MacOS 菜单,通过相对于活动项目定位 Select.Content。如果您更喜欢类似于 Popover 或 DropdownMenu 的替代定位方法,则可以将 position 设置为 popper,并使用额外的对齐选项,例如 side、sideOffset 等。

// index.jsx
import { Select } from "radix-ui";
export default () => (
<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content position="popper" sideOffset={5}>
</Select.Content>
</Select.Portal>
</Select.Root>
);

约束内容大小

当在 Select.Content 上使用 position="popper" 时,您可能希望约束内容的宽度,使其与触发器宽度匹配。您可能还希望约束其高度,使其不超过视口。

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

// index.jsx
import { Select } from "radix-ui";
import "./styles.css";
export default () => (
<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content className="SelectContent" position="popper" sideOffset={5} >
</Select.Content>
</Select.Portal>
</Select.Root>
);
/* styles.css */
.SelectContent {
width: var(--radix-select-trigger-width);
max-height: var(--radix-select-content-available-height);
}

带有禁用项目

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

// index.jsx
import { Select } from "radix-ui";
import "./styles.css";
export default () => (
<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Viewport>
<Select.Item className="SelectItem" disabled>
</Select.Item>
<Select.Item></Select.Item>
<Select.Item></Select.Item>
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>
);
/* styles.css */
.SelectItem[data-disabled] {
color: "gainsboro";
}

带有占位符

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

// index.jsx
import { Select } from "radix-ui";
import "./styles.css";
export default () => (
<Select.Root>
<Select.Trigger className="SelectTrigger">
<Select.Value placeholder="Pick an option" />
<Select.Icon />
</Select.Trigger>
<Select.Portal>
<Select.Content></Select.Content>
</Select.Portal>
</Select.Root>
);
/* styles.css */
.SelectTrigger[data-placeholder] {
color: "gainsboro";
}

带有分隔符

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

<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Viewport>
<Select.Item></Select.Item>
<Select.Item></Select.Item>
<Select.Item></Select.Item>
<Select.Separator />
<Select.Item></Select.Item>
<Select.Item></Select.Item>
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>

带有分组项目

使用 Group 和 Label 部分将项目分组到一个部分中。

<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Viewport>
<Select.Group>
<Select.Label>Label</Select.Label>
<Select.Item></Select.Item>
<Select.Item></Select.Item>
<Select.Item></Select.Item>
</Select.Group>
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>

带有复杂项目

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

import { Select } from "radix-ui";
export default () => (
<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Viewport>
<Select.Item>
<Select.ItemText>
<img src="" />
Adolfo Hess
</Select.ItemText>
<Select.ItemIndicator></Select.ItemIndicator>
</Select.Item>
<Select.Item></Select.Item>
<Select.Item></Select.Item>
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>
);

控制触发器中显示的值

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

如果您需要更大的灵活性,可以使用 value/onValueChange 属性控制组件,并将 children 传递给 SelectValue。请记住确保您放入其中的内容是可访问的。

const countries = { france: "🇫🇷", "united-kingdom": "🇬🇧", spain: "🇪🇸" };
export default () => {
const [value, setValue] = React.useState("france");
return (
<Select.Root value={value} onValueChange={setValue}>
<Select.Trigger>
<Select.Value aria-label={value}>
{countries[value]}
</Select.Value>
<Select.Icon />
</Select.Trigger>
<Select.Portal>
<Select.Content>
<Select.Viewport>
<Select.Item value="france">
<Select.ItemText>France</Select.ItemText>
<Select.ItemIndicator></Select.ItemIndicator>
</Select.Item>
<Select.Item value="united-kingdom">
<Select.ItemText>United Kingdom</Select.ItemText>
<Select.ItemIndicator></Select.ItemIndicator>
</Select.Item>
<Select.Item value="spain">
<Select.ItemText>Spain</Select.ItemText>
<Select.ItemIndicator></Select.ItemIndicator>
</Select.Item>
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select.Root>
);
};

带有自定义滚动条

原生滚动条默认情况下是隐藏的,因为我们建议使用 ScrollUpButton 和 ScrollDownButton 部分以获得最佳的用户体验。如果您不想使用这些部分,请使用我们的 Scroll Area 原始组件组合您的选择组件。

// index.jsx
import { Select, ScrollArea } from "radix-ui";
import "./styles.css";
export default () => (
<Select.Root>
<Select.Trigger></Select.Trigger>
<Select.Portal>
<Select.Content>
<ScrollArea.Root className="ScrollAreaRoot" type="auto">
<Select.Viewport asChild>
<ScrollArea.Viewport className="ScrollAreaViewport">
<StyledItem></StyledItem>
<StyledItem></StyledItem>
<StyledItem></StyledItem>
</ScrollArea.Viewport>
</Select.Viewport>
<ScrollArea.Scrollbar className="ScrollAreaScrollbar" orientation="vertical" >
<ScrollArea.Thumb className="ScrollAreaThumb" />
</ScrollArea.Scrollbar>
</ScrollArea.Root>
</Select.Content>
</Select.Portal>
</Select.Root>
);
/* 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);
border-radius: 3px;
}

可访问性

遵循 ListBox WAI-ARIA 设计模式

有关更多信息,请参阅 W3C Select-Only Combobox 示例。

键盘交互

按键描述
空格键
当焦点在 Select.Trigger 上时,打开选择组件并聚焦所选项。
当焦点在一个项目上时,选择聚焦的项目。
回车键
当焦点在 Select.Trigger 上时,打开选择组件并聚焦第一个项目。
当焦点在一个项目上时,选择聚焦的项目。
向下箭头
当焦点在 Select.Trigger 上时,打开选择组件。
当焦点在一个项目上时,将焦点移动到下一个项目。
向上箭头
当焦点在 Select.Trigger 上时,打开选择组件。
当焦点在一个项目上时,将焦点移动到上一个项目。
Esc 键
关闭选择组件并将焦点移动到 Select.Trigger。

标签

使用我们的 Label 组件,以便为选择组件提供可视化且可访问的标签。

import { Select, Label } from "radix-ui";
export default () => (
<>
<Label>
Country
<Select.Root></Select.Root>
</Label>
{/* or */}
<Label htmlFor="country">Country</Label>
<Select.Root>
<Select.Trigger id="country"></Select.Trigger>
<Select.Portal>
<Select.Content></Select.Content>
</Select.Portal>
</Select.Root>
</>
);

自定义 API

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

抽象为 Select 和 SelectItem

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

用法

import { Select, SelectItem } from "./your-select";
export default () => (
<Select defaultValue="2">
<SelectItem value="1">Item 1</SelectItem>
<SelectItem value="2">Item 2</SelectItem>
<SelectItem value="3">Item 3</SelectItem>
</Select>
);

实现

// your-select.jsx
import * as React from "react";
import { Select as SelectPrimitive } from "radix-ui";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon, } from "@radix-ui/react-icons";
export const Select = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<SelectPrimitive.Root {...props}>
<SelectPrimitive.Trigger ref={forwardedRef}>
<SelectPrimitive.Value />
<SelectPrimitive.Icon>
<ChevronDownIcon />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
<SelectPrimitive.Portal>
<SelectPrimitive.Content>
<SelectPrimitive.ScrollUpButton>
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>
<SelectPrimitive.Viewport>{children}</SelectPrimitive.Viewport>
<SelectPrimitive.ScrollDownButton>
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
</SelectPrimitive.Root>
);
},
);
export const SelectItem = React.forwardRef(
({ children, ...props }, forwardedRef) => {
return (
<SelectPrimitive.Item {...props} ref={forwardedRef}>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
<SelectPrimitive.ItemIndicator>
<CheckIcon />
</SelectPrimitive.ItemIndicator>
</SelectPrimitive.Item>
);
},
);
上一个滚动区域
下一个分隔符