JGuang

选择器

Select · Material UI

交互预览
npm install @mui/material@9.4.0 @emotion/react@11.14.0 @emotion/styled@11.14.1

选择器

通过原生或 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否boolfalse
children否node—
classes否object{}
defaultOpen否boolfalse
defaultValue否any—
displayEmpty否boolfalse
IconComponent否elementTypeArrowDropDownIcon
id否string—
input否element—
inputProps否object—
label否node—
labelId否string—
MenuProps否object—
multiple否boolfalse
native否boolfalse
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否elementTypeArrowDropDownIcon
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,不标为全文中文化。