Components

选择

¥Select

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

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;

Features

    Can be controlled or uncontrolled.

    Offers 2 positioning modes.

    Supports items, labels, groups of items.

    Focus is fully managed.

    Full keyboard navigation.

    Supports custom placeholder.

    Typeahead support.

    Supports Right to Left direction.

安装

¥Installation

从命令行安装组件。

¥Install the component from your command line.

npm install @radix-ui/react-select

结构

¥Anatomy

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

¥Import all parts and piece them together.

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 参考

¥API Reference

¥Root

包含选择框的所有部分。

¥Contains all the parts of a select.

PropTypeDefault
defaultValue
string
No default value
value
string
No default value
onValueChange
function
No default value
defaultOpen
boolean
No default value
open
boolean
No default value
onOpenChange
function
No default value
dir
enum
No default value
name
string
No default value
disabled
boolean
No default value
required
boolean
No default value

触发器

¥Trigger

切换选择按钮。Select.Content 将通过对齐触发器进行自我定位。

¥The button that toggles the select. The Select.Content will position itself by aligning over the trigger.

PropTypeDefault
asChild
boolean
false
Data attributeValues
[data-state]"open" | "closed"
[data-disabled]

Present when disabled

[data-placeholder]

Present when has placeholder

¥Value

反映所选值的部分。默认情况下,将渲染所选项目的文本。如果你需要更多控制,你可以控制选择并传递你自己的 children。它不应该被设计成确保正确定位的样式。当 select 没有值时,也可以使用可选的 placeholder 属性。

¥The part that reflects the selected value. By default the selected item's text will be rendered. if you require more control, you can instead control the select and pass your own children. It should not be styled to ensure correct positioning. An optional placeholder prop is also available for when the select has no value.

PropTypeDefault
asChild
boolean
false
placeholder
ReactNode
No default value

图标

¥Icon

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

¥A small icon often displayed next to the value as a visual affordance for the fact it can be open. By default renders ▼ but you can use your own icon via asChild or use children.

PropTypeDefault
asChild
boolean
false

门户

¥Portal

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

¥When used, portals the content part into the body.

PropTypeDefault
container
HTMLElement
document.body

内容

¥Content

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

¥The component that pops out when the select is open.

PropTypeDefault
asChild
boolean
false
onCloseAutoFocus
function
No default value
onEscapeKeyDown
function
No default value
onPointerDownOutside
function
No default value
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 attributeValues
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
CSS VariableDescription
--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".

视口

¥Viewport

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

¥The scrolling viewport that contains all of the items.

PropTypeDefault
asChild
boolean
false

项目

¥Item

包含选择项的组件。

¥The component that contains the select items.

PropTypeDefault
asChild
boolean
false
value*
string
No default value
disabled
boolean
No default value
textValue
string
No default value
Data attributeValues
[data-state]"checked" | "unchecked"
[data-highlighted]

Present when highlighted

[data-disabled]

Present when disabled

ItemText

项目的文本部分。它应该只包含你希望在选择该项目时在触发器中看到的文本。它不应该被设计成确保正确定位的样式。

¥The textual part of the item. It should only contain the text you want to see in the trigger when that item is selected. It should not be styled to ensure correct positioning.

PropTypeDefault
asChild
boolean
false

ItemIndicator

当项目被选中时渲染。你可以直接设置此元素的样式,也可以将其用作封装器来放置图标,或者两者兼而有之。

¥Renders when the item is selected. You can style this element directly, or you can use it as a wrapper to put an icon into, or both.

PropTypeDefault
asChild
boolean
false

ScrollUpButton

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

¥An optional button used as an affordance to show the viewport overflow as well as functionaly enable scrolling upwards.

PropTypeDefault
asChild
boolean
false

ScrollDownButton

一个可选的按钮,用作显示视口溢出的功能,并在功能上支持向下滚动。

¥An optional button used as an affordance to show the viewport overflow as well as functionaly enable scrolling downwards.

PropTypeDefault
asChild
boolean
false

¥Group

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

¥Used to group multiple items. use in conjunction with Select.Label to ensure good accessibility via automatic labelling.

PropTypeDefault
asChild
boolean
false

标签

¥Label

用于渲染组的标签。它无法通过方向键获得焦点。

¥Used to render the label of a group. It won't be focusable using arrow keys.

PropTypeDefault
asChild
boolean
false

分隔符

¥Separator

用于在选择框中以视觉方式分隔项目。

¥Used to visually separate items in the select.

PropTypeDefault
asChild
boolean
false

箭头

¥Arrow

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

¥An optional arrow element to render alongside the content. This can be used to help visually link the trigger with the Select.Content. Must be rendered inside Select.Content. Only available when position is set to popper.

PropTypeDefault
asChild
boolean
false
width
number
10
height
number
5

示例

¥Examples

更改定位模式

¥Change the positioning mode

默认情况下,Select 的行为类似于原生 MacOS 菜单,Select.Content 相对于活动项目进行定位。如果你更喜欢类似于 PopoverDropdownMenu 的替代定位方法,则可以将 position 设置为 popper,并使用其他对齐选项,例如 sidesideOffset 等。

¥By default, Select will behave similarly to a native MacOS menu by positioning Select.Content relative to the active item. If you would prefer an alternative positioning approach similar to Popover or DropdownMenu then you can set position to popper and make use of additional alignment options such as side, sideOffset and more.

// 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>
);

限制内容大小

¥Constrain the content size

Select.Content 上使用 position="popper" 时,可能需要限制内容的宽度,使其与触发器宽度匹配。你可能还需要限制其高度,使其不超过视口。

¥When using position="popper" on Select.Content, you may want to constrain the width of the content so that it matches the trigger width. You may also want to constrain its height to not exceed the viewport.

为了支持此功能,我们公开了几个 CSS 自定义属性,例如 --radix-select-trigger-width--radix-select-content-available-height。使用它们来限制内容尺寸。

¥We expose several CSS custom properties such as --radix-select-trigger-width and --radix-select-content-available-height to support this. Use them to constrain the content dimensions.

// 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);
}

使用禁用元素

¥With disabled items

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

¥You can add special styles to disabled items via the data-disabled attribute.

// 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";
}

使用占位符

¥With a placeholder

当选择项没有值时,你可以在 Value 上使用 placeholder 属性。Trigger 元素上还有一个 data-placeholder 属性,可用于设置样式。

¥You can use the placeholder prop on Value for when the select has no value. There's also a data-placeholder attribute on Trigger to help with styling.

// 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";
}

与分隔符一起使用

¥With separators

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

¥Use the Separator part to add a separator between items.

<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>

使用分组元素

¥With grouped items

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

¥Use the Group and Label parts to group items in a section.

<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>

使用复杂元素

¥With complex items

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

¥You can use custom content in your items.

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>
);

控制触发器中显示的值

¥Controlling the value displayed in the trigger

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

¥By default the trigger will automatically display the selected item ItemText's content. You can control what appears by chosing to put things inside/outside the ItemText part.

如果你需要更大的灵活性,你可以使用 value/onValueChange 属性来控制组件,并将 children 传递给 SelectValue。请务必确保你在其中输入的内容可访问。

¥If you need more flexibility, you can control the component using value/onValueChange props and passing children to SelectValue. Remember to make sure what you put in there is accessible.

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>
);
};

使用自定义滚动条

¥With custom scrollbar

原生滚动条默认隐藏,因为我们建议使用 ScrollUpButtonScrollDownButton 部分以获得最佳用户体验。如果你不想使用这些部分,请使用我们的 滚动区域 基础组件组合你的选择。

¥The native scrollbar is hidden by default as we recommend using the ScrollUpButton and ScrollDownButton parts for the best UX. If you do not want to use these parts, compose your select with our Scroll Area primitive.

// 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;
}

可访问性

¥Accessibility

遵循 列表框 WAI-ARIA 设计模式

¥Adheres to the ListBox WAI-ARIA design pattern.

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

¥See the W3C Select-Only Combobox example for more information.

键盘交互

¥Keyboard Interactions

KeyDescription
Space
When focus is on Select.Trigger, opens the select and focuses the selected item.
When focus is on an item, selects the focused item.
Enter
When focus is on Select.Trigger, opens the select and focuses the first item.
When focus is on an item, selects the focused item.
ArrowDown
When focus is on Select.Trigger, opens the select.
When focus is on an item, moves focus to the next item.
ArrowUp
When focus is on Select.Trigger, opens the select.
When focus is on an item, moves focus to the previous item.
Esc
Closes the select and moves focus to Select.Trigger.

标签

¥Labelling

使用我们的 标签 组件为选择项提供可视化且易于访问的标签。

¥Use our Label component in order to offer a visual and accessible label for the select.

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

¥Custom APIs

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

¥Create your own API by abstracting the primitive parts into your own component.

抽象至 SelectSelectItem

¥Abstract down to Select and SelectItem

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

¥This example abstracts most of the parts.

用法

¥Usage

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>
);

实现

¥Implementation

// 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>
);
},
);