选择器
通过原生或 Material 选择界面选择单值或多值。
本指南覆盖默认 Emotion 环境的 Material UI Core;扩展包与额外示例按清单单独标注。
使用场景与业务边界
多选需要正确数组类型;原生 option 与 MenuItem 的子结构不同,不可混用。
原生组成与范围
Select, NativeSelect
保持 Material UI 原生组合与类型,不替换为 JGuang/Base UI/Radix 同名 API。示例条目不是额外组件。
原生安装与初始化
npm install @mui/material@9.4.0 @emotion/react@11.14.0 @emotion/styled@11.14.1
采用原生 npm 包与 Emotion,不提供虚构的 JGuang UI Registry 地址。将示例放在原生 ThemeProvider 内,按项目选择 CssBaseline 或 ScopedCssBaseline。先检查 React、现有 Provider、锁文件与 SSR 配置;不要覆盖用户文件或忽略 peer 冲突。本批实际验收 React 19.2.8;React 18 及以下须匹配 react-is。完整初始化规则见随附的双语 setup 文档。
关键原生参数
仅解释本指南选出的关键参数,不是平铺的通用 API。原生继承来源、slot 结构、可空值与泛型仍按固定源码保留。
| 所属组件.属性 | 用途说明 | 声明来源 |
|---|---|---|
Select.value | 受控原生值,其单值/数组/可空类型取决于所属组件。 | Select |
Select.multiple | 原生多选模式,值与回调类型随所属组件变化。 | Select |
Select.onChange | 所属控件的原生回调,保留其准确事件/数值/可空签名。 | Select |
Select.labelId | 为原生 Select 提供名称的元素 ID,不可指向不存在的标签。 | Select |
Select.renderValue | 原生选中值展示回调,不改变选中数据。 | Select |
Select.native | 渲染浏览器原生 Select 子结构,而不是 MenuItem。 | Select |
可运行原生示例
下列机器键只选择示例入口,不会作为通用 variant 属性传入每个组件。原生示例 JSX 与数据保持上游原文;JGuang 编写的验收示例明确标注。
- 基础选择器 ·
BasicSelect· 上游原生示例 - 多种变体 ·
SelectVariants· 上游原生示例 - 标签与辅助说明 ·
SelectLabels· 上游原生示例 - 自适应宽度 ·
SelectAutoWidth· 上游原生示例 - 紧凑尺寸 ·
SelectSmall· 上游原生示例 - 其他属性 ·
SelectOtherProps· 上游原生示例 - 原生选择器 ·
NativeSelectDemo· 上游原生示例 - 定制样式 ·
CustomizedSelects· 上游原生示例 - 默认示例 ·
MultipleSelect· 上游原生示例 - 选择指示 ·
MultipleSelectCheckmarks· 上游原生示例 - 标签展示 ·
MultipleSelectChip· 上游原生示例 - 占位提示 ·
MultipleSelectPlaceholder· 上游原生示例 - 浏览器原生控件 ·
MultipleSelectNative· 上游原生示例 - 控制打开状态 ·
ControlledOpenSelect· 上游原生示例 - 在对话框中使用 ·
DialogSelect· 上游原生示例 - 选项分组 ·
GroupedSelect· 上游原生示例
真实使用示例
固定版本的未修改原生示例;复制时同时保留所需的局部辅助文件。
import * as React from 'react';
import Box from '@mui/material/Box';
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select, { SelectChangeEvent } from '@mui/material/Select';
export default function BasicSelect() {
const [age, setAge] = React.useState('');
const handleChange = (event: SelectChangeEvent) => {
setAge(event.target.value as string);
};
return (
<Box sx={{ minWidth: 120 }}>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">Age</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={age}
label="Age"
onChange={handleChange}
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</Box>
);
}
示例依赖边界
react, @mui/material/Box, @mui/material/InputLabel, @mui/material/MenuItem, @mui/material/FormControl, @mui/material/Select, @mui/material/FormHelperText, @mui/material/NativeSelect, @mui/material/styles, @mui/material/InputBase, @mui/material/OutlinedInput, @mui/material/ListItemText, @mui/icons-material/CheckBoxOutlineBlank, @mui/icons-material/CheckBox, @mui/material/Chip, @mui/material/Button, @mui/material/Dialog, @mui/material/DialogActions, @mui/material/DialogContent, @mui/material/DialogTitle, @mui/material/ListSubheader
直接导入 Icons/System/Utils 的示例需要匹配 9.4.0 包。局部数据与辅助文件属于示例闭包,不是额外组件。远程图片和模拟操作不提供后端。
固定上游 API 元数据参考
以下表格保留上游元数据,不是重新推断的通用类型体系。条件泛型、继承属性与回调细节以以下源码声明为准。主题默认配置可能覆盖元数据默认值。
Select
import Select from '@mui/material/Select';
import { Select } from '@mui/material';
原生继承: OutlinedInput. 父级与 DOM 属性未被伪造为本组件新属性。
| 属性 | 必需 | 上游元数据类型/约束 | 元数据默认值 |
|---|---|---|---|
autoWidth | 否 | bool | false |
children | 否 | node | — |
classes | 否 | object | {} |
defaultOpen | 否 | bool | false |
defaultValue | 否 | any | — |
displayEmpty | 否 | bool | false |
IconComponent | 否 | elementType | ArrowDropDownIcon |
id | 否 | string | — |
input | 否 | element | — |
inputProps | 否 | object | — |
label | 否 | node | — |
labelId | 否 | string | — |
MenuProps | 否 | object | — |
multiple | 否 | bool | false |
native | 否 | bool | false |
onChange | 否 | func | — |
onClose | 否 | func | — |
onOpen | 否 | func | — |
open | 否 | bool | — |
renderValue | 否 | func | — |
SelectDisplayProps | 否 | object | — |
sx | 否 | Array<func | object | bool> | func | object | — |
value | 否 | '' | any | — |
variant | 否 | 'filled' | 'outlined' | 'standard' | 'outlined' |
NativeSelect
import NativeSelect from '@mui/material/NativeSelect';
import { NativeSelect } from '@mui/material';
原生继承: Input. 父级与 DOM 属性未被伪造为本组件新属性。
| 属性 | 必需 | 上游元数据类型/约束 | 元数据默认值 |
|---|---|---|---|
children | 否 | node | — |
classes | 否 | object | {} |
IconComponent | 否 | elementType | ArrowDropDownIcon |
input | 否 | element | <Input /> |
inputProps | 否 | object | — |
onChange | 否 | func | — |
sx | 否 | Array<func | object | bool> | func | object | — |
value | 否 | any | — |
variant | 否 | 'filled' | 'outlined' | 'standard' | — |
原生源码声明
声明与 import 从固定源码提取,不平铺联合类型或外部继承。英文注释/类型属于原始源码参考,不代表上游正文已全文翻译。共享类型仍位于原生包中。
vendor/src/Select/Select.d.ts
import * as React from 'react';
import { SxProps } from '@mui/system';
import { Theme } from '../styles';
import { InternalStandardProps as StandardProps } from '../internal';
import { InputProps } from '../Input';
import { MenuProps } from '../Menu';
import { SelectChangeEvent, SelectInputProps } from './SelectInput';
import { SelectClasses } from './selectClasses';
import { OutlinedInputProps } from '../OutlinedInput';
import { FilledInputProps } from '../FilledInput';
export interface BaseSelectProps<Value = unknown> extends StandardProps<
InputProps,
'value' | 'onChange' | 'placeholder'
> {
/**
* If `true`, the width of the popover will automatically be set according to the items inside the
* menu, otherwise it will be at least the width of the select input.
* @default false
*/
autoWidth?: boolean | undefined;
/**
* The option elements to populate the select with.
* Can be some `MenuItem` when `native` is false and `option` when `native` is true.
*
* ⚠️The `MenuItem` elements **must** be direct descendants when `native` is false.
*/
children?: React.ReactNode;
/**
* Override or extend the styles applied to the component.
* @default {}
*/
classes?: Partial<SelectClasses> | undefined;
/**
* If `true`, the component is initially open. Use when the component open state is not controlled (i.e. the `open` prop is not defined).
* You can only use it when the `native` prop is `false` (default).
* @default false
*/
defaultOpen?: boolean | undefined;
/**
* The default value. Use when the component is not controlled.
*/
defaultValue?: Value | undefined;
/**
* If `true`, a value is displayed even if no items are selected.
*
* In order to display a meaningful value, a function can be passed to the `renderValue` prop which
* returns the value to be displayed when no items are selected.
*
* ⚠️ When using this prop, make sure the label doesn't overlap with the empty displayed value.
* The label should either be hidden or forced to a shrunk state.
* @default false
*/
displayEmpty?: boolean | undefined;
/**
* The icon that displays the arrow.
* @default ArrowDropDownIcon
*/
IconComponent?: React.ElementType | undefined;
/**
* The `id` of the wrapper element or the `select` element when `native`.
*/
id?: string | undefined;
/**
* An `Input` element; does not have to be a material-ui specific `Input`.
*/
input?: React.ReactElement<unknown, any> | undefined;
/**
* [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#attributes) applied to the `input` element.
* When `native` is `true`, the attributes are applied on the `select` element.
*/
inputProps?: InputProps['inputProps'] | undefined;
/**
* See [OutlinedInput#label](https://mui.com/material-ui/api/outlined-input/#props)
*/
label?: React.ReactNode;
/**
* The ID of an element that acts as an additional label. The Select will
* be labelled by the additional label and the selected value.
*/
labelId?: string | undefined;
/**
* Props applied to the [`Menu`](https://mui.com/material-ui/api/menu/) element.
*/
MenuProps?: Partial<MenuProps> | undefined;
/**
* If `true`, `value` must be an array and the menu will support multiple selections.
* @default false
*/
multiple?: boolean | undefined;
/**
* If `true`, the component uses a native `select` element.
* @default false
*/
native?: boolean | undefined;
/**
* Callback fired when a menu item is selected.
*
* @param {SelectChangeEvent<Value>} event The event source of the callback.
* You can pull out the new value by accessing `event.target.value` (any).
* **Warning**: This is a generic event, not a change event, unless the change event is caused by browser autofill.
* @param {object} [child] The react element that was selected when `native` is `false` (default).
*/
onChange?: SelectInputProps<Value>['onChange'] | undefined;
/**
* Callback fired when the component requests to be closed.
* Use it in either controlled (see the `open` prop), or uncontrolled mode (to detect when the Select collapses).
*
* @param {object} event The event source of the callback.
*/
onClose?: ((event: React.SyntheticEvent) => void) | undefined;
/**
* Callback fired when the component requests to be opened.
* Use it in either controlled (see the `open` prop), or uncontrolled mode (to detect when the Select expands).
*
* @param {object} event The event source of the callback.
*/
onOpen?: ((event: React.SyntheticEvent) => void) | undefined;
/**
* If `true`, the component is shown.
* You can only use it when the `native` prop is `false` (default).
*/
open?: boolean | undefined;
/**
* Render the selected value.
* You can only use it when the `native` prop is `false` (default).
*
* @param {any} value The `value` provided to the component.
* @returns {ReactNode}
*/
renderValue?: ((value: Value) => React.ReactNode) | undefined;
/**
* Props applied to the clickable div element.
*/
SelectDisplayProps?: React.HTMLAttributes<HTMLDivElement> | undefined;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme> | undefined;
/**
* The `input` value. Providing an empty string will select no options.
* Set to an empty string `''` if you don't want any of the available options to be selected.
*
* If the value is an object it must have reference equality with the option in order to be selected.
* If the value is not an object, the string representation must match with the string representation of the option in order to be selected.
*/
value?: Value | '' | undefined;
/**
* The variant to use.
* @default 'outlined'
*/
variant?: SelectVariants | undefined;
}
export interface FilledSelectProps extends Omit<
FilledInputProps,
'value' | 'onChange' | 'id' | 'classes' | 'inputProps' | 'placeholder' | 'label'
> {
/**
* The variant to use.
* @default 'outlined'
*/
variant: 'filled';
}
export interface StandardSelectProps extends Omit<
InputProps,
'value' | 'onChange' | 'id' | 'classes' | 'inputProps' | 'placeholder' | 'label'
> {
/**
* The variant to use.
* @default 'outlined'
*/
variant: 'standard';
}
export interface OutlinedSelectProps extends Omit<
OutlinedInputProps,
'value' | 'onChange' | 'id' | 'classes' | 'inputProps' | 'placeholder' | 'label'
> {
/**
* The variant to use.
* @default 'outlined'
*/
variant?: 'outlined' | undefined;
}
export type SelectVariants = 'outlined' | 'standard' | 'filled';
export type SelectProps<Value = unknown> =
| (FilledSelectProps & BaseSelectProps<Value>)
| (StandardSelectProps & BaseSelectProps<Value>)
| (OutlinedSelectProps & BaseSelectProps<Value>);
declare const Select: (<Value = unknown>(props: SelectProps<Value>) => React.JSX.Element) & {
muiName: string;
};
vendor/src/NativeSelect/NativeSelect.d.ts
import * as React from 'react';
import { SxProps } from '@mui/system';
import { Theme } from '../styles';
import { InternalStandardProps as StandardProps } from '../internal';
import { InputProps } from '../Input';
import { NativeSelectInputProps } from './NativeSelectInput';
import { NativeSelectClasses } from './nativeSelectClasses';
export interface NativeSelectProps extends StandardProps<
InputProps,
'inputProps' | 'value' | 'onChange'
> {
/**
* The option elements to populate the select with.
* Can be some `<option>` elements.
*/
children?: React.ReactNode;
/**
* Override or extend the styles applied to the component.
* @default {}
*/
classes?: Partial<NativeSelectClasses> | undefined;
/**
* The icon that displays the arrow.
* @default ArrowDropDownIcon
*/
IconComponent?: React.ElementType | undefined;
/**
* An `Input` element; does not have to be a material-ui specific `Input`.
* @default <Input />
*/
input?: React.ReactElement<unknown, any> | undefined;
/**
* [Attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select#attributes) applied to the `select` element.
*/
inputProps?: Partial<NativeSelectInputProps> | undefined;
/**
* Callback fired when a menu item is selected.
*
* @param {React.ChangeEvent<HTMLSelectElement>} event The event source of the callback.
* You can pull out the new value by accessing `event.target.value` (string).
*/
onChange?: NativeSelectInputProps['onChange'] | undefined;
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx?: SxProps<Theme> | undefined;
/**
* The `input` value. The DOM API casts this to a string.
*/
value?: unknown;
/**
* The variant to use.
*/
variant?: 'standard' | 'outlined' | 'filled' | undefined;
}
declare const NativeSelect: ((props: NativeSelectProps) => React.JSX.Element) & { muiName: string };
安装后验收
执行严格类型检查、生产构建和实际交互。检查键盘标签/焦点、原生支持的禁用/错误/只读语义、深浅色、窄屏和减少动画。按真实宿主数据检查回调,不把复制提示词当作安装完成。初始化工具还需检查服务端 HTML 与无告警水合。
来源与许可
https://github.com/mui/material-ui/tree/809a7717b4c050ba3f69b75300689f07c050a16e
MIT · @mui/material@9.4.0. 保留上游原始内容与许可证。上游完整原文保留于 vendor/docs,不标为全文中文化。