选择器
Mantine Core 的独立组件,请不要替换为 JGuang UI/Base UI 的同名 API。
安装
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1
入口引入 @mantine/core/styles.css,并在根组件使用 MantineProvider;通过 forceColorScheme 同步深浅色主题。
使用与验证
在左侧选择组件,在预览中操作它的状态;使用“查看代码”检查真实源码。安装后执行类型检查和构建,再验证键盘焦点、手机布局与深浅色主题。
来源
https://github.com/mantinedev/mantine/tree/f0e2bc6d28b0f0b8aaefb5b859937bf77f539df7 MIT 许可证;不包括付费内容。下方提供上游英文参考内容,中文使用指南已适配;上游详细参考暂保留英文。
版本与兼容性
固定的 Mantine Core 9.7.1 要求 React 和 React DOM 满足 ^19.2.0,并配套 @mantine/hooks@9.7.1。此条件来自实际 npm 包的 peerDependencies。React 18 或其他不兼容版本不能强行安装;先向项目负责人说明升级影响并确认方案,不使用 --force/--legacy-peer-deps 掩盖冲突。入口的原生 Provider 开启 theme.respectReducedMotion,并用 forceColorScheme 控制深浅色。
适用场景
从可搜索的列表中选择单个值。
本地示例使用的原生参数
以下参数由本地、经过类型检查的 JSX 示例提取,按所属组件区分。不是全部属性清单;完整签名和继承关系见下方固定源码参考。
| 组件参数 | 说明 |
|---|---|
Select.disabled | 禁用用户输入或操作,不等同于只读。 |
Select.error | 本地错误展示,本身不执行校验。 |
Select.readOnly | 阻止编辑并保留只读交互。 |
Select.label | 可见标签或当前组件的标签内容。 |
Select.data | 本地选项或节点,保持 value 唯一并遵循原生结构。 |
Select.searchable | 启用当前组件的本地搜索交互。 |
交互与状态检查
当前场景:默认、禁用、校验错误、只读。切换支持的禁用、错误或只读场景后检查真实行为;无此原生状态的组件不会被强行添加统一属性。验证键盘焦点和退出方式,修改值后按原生回调签名连接业务状态。
业务接入边界
单选值可为空。data 的值类型应与 value/onChange 一致;展示标签不是提交值。
宿主配置
先安装固定版本 @mantine/core 和 @mantine/hooks,在入口引入 @mantine/core/styles.css,并使用 MantineProvider。示例的 theme 和 variant 是 JGuang 编写的宿主参数,不是所有原生组件都接受的统一 API;通过 forceColorScheme 同步应用主题。源码面板中的原生实现仅供阅读,使用 npm 导出,不要单独复制内部实现。此批只覆盖 Core,不包括日期、图表和表单扩展包。上游详细说明保留英文,不宣称全文中文化。
可运行用法
以下代码使用资源原生 API;不是把其他设计系统的同名组件替换进来。
import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';
const fruit = ["Apple", "Banana", "Orange"];
function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const disabled = variant === "Disabled";
const invalid = variant === "Invalid";
const readOnly = variant === "Read only";
return <M.Select disabled={disabled} error={invalid ? "Choose a fruit / 请选择水果" : undefined} readOnly={readOnly} label="Fruit" data={fruit} searchable />;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}
可用状态与示例
默认、禁用、校验错误、只读
示例遵循 Mantine 原生 API。支持多状态的输入组件可将示例中的 variant 改为 Disabled、Invalid 或 Read only;这些只是示例标签,不是新增的组件属性。改造时保留组件要求的数据、受控值、store 和复合子组件结构。
Usage
Select allows capturing user input based on suggestions from a list.
Unlike Autocomplete, Select does not allow entering custom values.
Loading state
Set loading prop to display a loading indicator. By default, the loader is displayed on the right side of the input.
This is useful for async operations like API calls, searches, or validations:
Controlled
The Select value must be a primitive type (string, number, or boolean).
The onChange function is called with a primitive value as a single argument.
import { useState } from 'react';
import { Select } from '@mantine/core';
function Demo() {
const [value, setValue] = useState<string | null>('');
return <Select data={[]} value={value} onChange={setValue} />;
}
onChange handler
onChange is called with two arguments:
value- string value of the selected optionoption– selected option object
If you prefer the object format in state, use the second argument of the onChange handler:
import { useState } from 'react';
import { ComboboxItem, Select } from '@mantine/core';
function Demo() {
const [value, setValue] = useState<ComboboxItem | null>(null);
return (
<Select
data={[{ value: 'react', label: 'React library' }]}
value={value ? value.value : null}
onChange={(_value, option) => setValue(option)}
/>
);
}
autoSelectOnBlur
Set the autoSelectOnBlur prop to automatically select the highlighted option when the input loses focus.
Note: This prop only has an effect when searchable is set to true. To see this feature in action: select an option with the up/down arrows, then click outside the input:
Clearable
Set the clearable prop to display the clear button in the right section. The button is not displayed
when:
- The component does not have a value
- The component is disabled
- The component is read only
Allow deselect
The allowDeselect prop determines whether the value should be deselected when the user clicks on the selected option.
By default, allowDeselect is true:
Open on focus
Set the openOnFocus prop to open the dropdown when the input receives focus.
Note: This prop only has an effect when searchable is set to true:
Searchable
Set the searchable prop to allow filtering options by user input:
Controlled search value
You can control the search value with searchValue and onSearchChange props:
import { useState } from 'react';
import { Select } from '@mantine/core';
function Demo() {
const [searchValue, setSearchValue] = useState('');
return (
<Select
searchable
searchValue={searchValue}
onSearchChange={setSearchValue}
data={[]}
/>
);
}
Nothing found
Set the nothingFoundMessage prop to display a given message when no options match the search query
or there is no data available. If the nothingFoundMessage prop is not set, the Select dropdown will be hidden.
Checked option icon
Set checkIconPosition prop to left or right to control position of check icon in active option.
To remove the check icon, set withCheckIcon={false}. To align unchecked labels with the checked one, set withAlignedLabels prop.
Value type
Select supports primitive values (strings, numbers, booleans) as value type. Select automatically
infers the value type. If you want to set the value type explicitly, pass type argument:
import { Select } from '@mantine/core';
type SelectValue = 'React' | 'Angular' | 'Svelte' | number;
function Demo() {
return <Select<SelectValue> data={['React', 'Angular', 'Svelte', 100]} />;
}
Sort options
By default, options are sorted by their position in the data array. You can change this behavior
with the filter function:
Fuzzy search with fuse.js
You can implement fuzzy search using the fuse.js library to match options even with typos or partial matches:
renderOption
The renderOption callback allows you to customize option rendering. It is called with an option object and
checked state. The function must return a React node.
Scrollable dropdown
By default, the options list is wrapped with ScrollArea.Autosize.
You can control the dropdown max-height with the maxDropdownHeight prop if you do not change the default settings.
If you want to use native scrollbars, set withScrollArea={false}. Note that in this case,
you will need to change the dropdown styles with Styles API.
Fit dropdown to viewport height
Set floatingHeight="viewport" to make the dropdown grow to fill the available vertical
space in the viewport. The flip middleware is disabled in this mode – the dropdown
always opens in the configured direction and is constrained to the viewport edges instead
of flipping to the other side. Useful when working with large option lists:
Group options
The group property accepts any React node, so you can render custom markup
(icons, badges, styled text) as a group label instead of a plain string. This
also applies to MultiSelect, Autocomplete and TagsInput. Note that
NativeSelect renders native optgroup elements and only supports string
group labels.
Disabled options
When an option is disabled, it cannot be selected and is ignored in keyboard navigation.
Inside Popover
To use Select inside popover, you need to set withinPortal: false:
Control dropdown opened state
You can control the dropdown opened state with the dropdownOpened prop. Additionally,
you can use onDropdownClose and onDropdownOpen to listen to dropdown opened state changes.
Dropdown position
By default, the dropdown is displayed below the input if there is enough space; otherwise it is displayed above the input.
You can change this behavior by setting the position and middlewares props, which are passed down to the
underlying Popover component.
Example of a dropdown that is always displayed above the input:
Dropdown width
To change the dropdown width, set the width prop in comboboxProps. By default,
the dropdown width is equal to the input width.
Dropdown offset
To change the dropdown offset, set the offset prop in comboboxProps:
Prevent horizontal infinite scrolling
If you experience horizontal infinite scrolling in the dropdown, set the shift middleware padding to 0:
import { Select } from '@mantine/core';
function Demo() {
return (
<Select
data={['React', 'Angular', 'Vue']}
comboboxProps={{
middlewares: {
shift: { padding: 0 }
}
}}
/>
);
}
Dropdown animation
By default, dropdown animations are disabled. To enable them, you can set transitionProps,
which will be passed down to the underlying Transition component.
Dropdown padding
Dropdown shadow
Input props
Read only
Set readOnly to make the input read only. When readOnly is set,
Select will not show suggestions and will not call the onChange function.
Disabled
Set disabled to disable the input. When disabled is set,
the user cannot interact with the input and Select will not show suggestions.
Error state
Success state
To set aria-label on the clear button, use clearButtonProps. Note that this is required
only when clearable is set.
import { Select } from '@mantine/core';
function Demo() {
return (
<Select
data={[]}
clearable
clearButtonProps={{
'aria-label': 'Clear input',
}}
/>
);
}
源码参数参考
以下实现签名和类型从本地固定版本源码生成。保留可选属性、原生继承类型、联合分支和 never 限制;不会将其他设计系统的 API 混入。forwardRef 实现中的 ref 属于 React 引用,不是新增业务属性。此区域是原始类型参考,不是上游说明的全文翻译。
Select(_props)
export type SelectStylesNames = __InputStylesNames | ComboboxLikeStylesNames;
export interface SelectProps<Value extends Primitive = string>
extends
BoxProps,
__BaseInputProps,
ComboboxLikeProps<Value>,
StylesApiProps<SelectFactory>,
ElementProps<'input', 'onChange' | 'size' | 'value' | 'defaultValue'> {
/** Controlled component value */
value?: Value | null;
/** Uncontrolled component default value */
defaultValue?: Value | null;
/** Called when value changes */
onChange?: (value: Value | null, option: ComboboxItem<Value>) => void;
/** Called when the clear button is clicked */
onClear?: () => void;
/** Determines whether the select should be searchable @default false */
searchable?: boolean;
/** Displays check icon near the selected option label @default true */
withCheckIcon?: boolean;
/** Aligns unchecked labels with the checked one @default false */
withAlignedLabels?: boolean;
/** Position of the check icon relative to the option label @default 'left' */
checkIconPosition?: 'left' | 'right';
/** Message displayed when no options match the search query or when there is no data */
nothingFoundMessage?: React.ReactNode;
/** Controlled search value */
searchValue?: string;
/** Default search value */
defaultSearchValue?: string;
/** Called when search changes */
onSearchChange?: (value: string) => void;
/** Allows deselecting the selected option by clicking it @default true */
allowDeselect?: boolean;
/** Displays clear button in the right section when component has value @default false */
clearable?: boolean;
/** Determines how the clear button and rightSection are rendered @default 'both' */
clearSectionMode?: ClearSectionMode;
/** Props passed down to the clear button */
clearButtonProps?: InputClearButtonProps;
/** Props passed down to the hidden input */
hiddenInputProps?: Omit<React.ComponentProps<'input'>, 'value'>;
/** A function to render content of the option, replaces the default content of the option */
renderOption?: (item: ComboboxLikeRenderOptionInput<ComboboxItem<Value>>) => React.ReactNode;
/** Props passed down to the underlying `ScrollArea` component in the dropdown */
scrollAreaProps?: ScrollAreaProps;
/** Controls color of the default chevron, by default depends on the color scheme */
chevronColor?: MantineColor;
/** Automatically selects the highlighted option when input loses focus @default false */
autoSelectOnBlur?: boolean;
/** Opens dropdown when input receives focus (requires searchable={true}) @default true */
openOnFocus?: boolean;
}
export type SelectFactory = Factory<{
props: SelectProps;
ref: HTMLInputElement;
stylesNames: SelectStylesNames;
variant: InputVariant;
signature: <Value extends Primitive = string>(props: SelectProps<Value>) => React.JSX.Element;
}>;
export type Mod = Record<string, any> | string;
export type BoxMod = Mod | Mod[] | BoxMod[];
export interface BoxProps extends MantineStyleProps {
/** Class added to the root element, if applicable */
className?: string | undefined;
/** Inline style added to root component element, can subscribe to theme defined on MantineProvider */
style?: MantineStyleProp;
/** CSS variables defined on root component element */
__vars?: CssVarsProp;
/** `size` property passed down the HTML element */
__size?: string;
/** Breakpoint above which the component is hidden with `display: none` */
hiddenFrom?: MantineBreakpoint;
/** Breakpoint below which the component is hidden with `display: none` */
visibleFrom?: MantineBreakpoint;
/** Determines whether component should be hidden in light color scheme with `display: none` */
lightHidden?: boolean;
/** Determines whether component should be hidden in dark color scheme with `display: none` */
darkHidden?: boolean;
/** Element modifiers transformed into `data-` attributes, for example, `{ 'data-size': 'xl' }`, falsy values are removed */
mod?: BoxMod;
}
export type ElementProps<
ElementType extends React.ElementType,
PropsToOmit extends string = never,
> = Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>;
export interface CSSProperties extends React.CSSProperties {
[key: string]: any;
}
type MantineStyle = CSSProperties | ((theme: MantineTheme) => CSSProperties);
export type MantineStyleProp = MantineStyle | MantineStyle[] | MantineStyleProp[] | undefined;
export type CssVariable = `--${string}`;
export type CssVariables<Variable extends string = CssVariable> = Partial<Record<Variable, string>>;
export type CssVars<Variable extends string = CssVariable> =
| CssVariables<Variable>
| ((theme: MantineTheme) => CssVariables<Variable>)
| CssVars<Variable>[];
export type CssVarsProp<Variable extends string = CssVariable> =
| CssVars<Variable>
| CssVars<Variable>[];
type WrapperProps = React.ComponentProps<'div'> & DataAttributes;
export interface __BaseInputProps extends __InputWrapperProps, __InputProps {
/** Props passed down to the root element */
wrapperProps?: WrapperProps;
}
export type __InputStylesNames = InputStylesNames | InputWrapperStylesNames;
export type InputStylesNames = 'input' | 'wrapper' | 'section' | 'bottomSection';
export type InputVariant = 'default' | 'filled' | 'unstyled';
export interface __InputProps {
/** Content section displayed on the left side of the input */
leftSection?: React.ReactNode;
/** Left section width, used to set `width` of the section and input `padding-left`, by default equals to the input height */
leftSectionWidth?: React.CSSProperties['width'];
/** Props passed down to the `leftSection` element */
leftSectionProps?: React.ComponentProps<'div'>;
/** Sets `pointer-events` styles on the `leftSection` element. Use `'all'` when section contains interactive elements (buttons, links). @default 'none' */
leftSectionPointerEvents?: React.CSSProperties['pointerEvents'];
/** Content section displayed on the right side of the input */
rightSection?: React.ReactNode;
/** Right section width, used to set `width` of the section and input `padding-right`, by default equals to the input height */
rightSectionWidth?: React.CSSProperties['width'];
/** Props passed down to the `rightSection` element */
rightSectionProps?: React.ComponentProps<'div'>;
/** Sets `pointer-events` styles on the `rightSection` element. Use `'all'` when section contains interactive elements (buttons, links). @default 'none' */
rightSectionPointerEvents?: React.CSSProperties['pointerEvents'];
/** Sets `required` attribute on the `input` element */
required?: boolean;
/** Key of `theme.radius` or any valid CSS value to set `border-radius`, numbers are converted to rem @default theme.defaultRadius */
radius?: MantineRadius;
/** Sets `disabled` attribute on the `input` element */
disabled?: boolean;
/** Controls input `height`, horizontal `padding`, and `font-size` @default 'sm' */
size?: MantineSize | (string & {});
/** Determines whether the input should have `cursor: pointer` style. Use when input acts as a button-like trigger (e.g., `component="button"` for Select/DatePicker). @default false */
pointer?: boolean;
/** Determines whether the input should have red border and red text color when the `error` prop is set @default true */
withErrorStyles?: boolean;
/** Determines whether the input should have green border when the `success` prop is set @default true */
withSuccessStyles?: boolean;
/** HTML `size` attribute for the input element (number of visible characters) */
inputSize?: string;
/** Section to be displayed when the input is `__clearable` and `rightSection` is not defined */
__clearSection?: React.ReactNode;
/** Determines whether the `__clearSection` should be displayed if it is passed to the component, has no effect if `rightSection` is defined */
__clearable?: boolean;
/** Determines how the clear button and rightSection are rendered @default 'both' */
__clearSectionMode?: ClearSectionMode;
/** Right section displayed when both `__clearSection` and `rightSection` are not defined */
__defaultRightSection?: React.ReactNode;
/** Displays loading indicator in the left or right section @default false */
loading?: boolean;
/** Position of the loading indicator @default 'right' */
loadingPosition?: 'left' | 'right';
/** Content section displayed at the bottom of the input, inside the border */
__bottomSection?: React.ReactNode;
/** Props passed down to the `__bottomSection` element */
__bottomSectionProps?: React.ComponentProps<'div'>;
}
export type InputWrapperStylesNames =
| 'root'
| InputLabelStylesNames
| InputDescriptionStylesNames
| InputErrorStylesNames
| InputSuccessStylesNames;
export interface __InputWrapperProps {
/** Contents of `Input.Label` component. If not set, label is not displayed. */
label?: React.ReactNode;
/** Contents of `Input.Description` component. If not set, description is not displayed. */
description?: React.ReactNode;
/** Contents of `Input.Error` component. If not set, error is not displayed. */
error?: React.ReactNode;
/** Contents of `Input.Success` component. If not set, success is not displayed. */
success?: React.ReactNode;
/** Adds required attribute to the input and a red asterisk on the right side of label @default false */
required?: boolean;
/** If set, the required asterisk is displayed next to the label. Overrides `required` prop. Does not add required attribute to the input. @default false */
withAsterisk?: boolean;
/** Props passed down to the `Input.Label` component */
labelProps?: InputLabelProps & DataAttributes & PlaceholderPolymorphicProps;
/** Props passed down to the `Input.Description` component */
descriptionProps?: InputDescriptionProps & DataAttributes & PlaceholderPolymorphicProps;
/** Props passed down to the `Input.Error` component */
errorProps?: InputErrorProps & DataAttributes & PlaceholderPolymorphicProps;
/** Props passed down to the `Input.Success` component */
successProps?: InputSuccessProps & DataAttributes & PlaceholderPolymorphicProps;
/** Render function to wrap the input element. Useful for adding tooltips, popovers, or other wrappers around the input. @default React.Fragment */
inputContainer?: (children: React.ReactNode) => React.ReactNode;
/** Controls order and visibility of wrapper elements. Only elements included in this array will be rendered. @default ['label', 'description', 'input', 'error'] */
inputWrapperOrder?: ('label' | 'input' | 'description' | 'error')[];
}
原生与外部类型
以下外部类型仍由 React 或资源自身依赖定义,没有手工展开为虚构属性。实际可用类型以安装版本的 TypeScript 检查为准。
Factory<{
props: SelectProps;
ref: HTMLInputElement;
stylesNames: SelectStylesNames;
variant: InputVariant;
signature: <Value extends Primitive = string>(props: SelectProps<Value>) => React.JSX.Element;
}>
Primitive
MantineStyleProps
React.CSSProperties
MantineTheme
Partial<Record<Variable, string>>
Record<Variable, string>
Variable
MantineBreakpoint
Record<string, any>
React.ReactNode
InputLabelProps
DataAttributes
PlaceholderPolymorphicProps
InputDescriptionProps
InputErrorProps
InputSuccessProps
React.ComponentProps<'div'>
MantineRadius
MantineSize
ClearSectionMode
ComboboxLikeProps<Value>
Value
StylesApiProps<SelectFactory>
React.ElementType
Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>
React.ComponentProps<ElementType>
ElementType
PropsToOmit
ComboboxItem<Value>
InputClearButtonProps
Omit<React.ComponentProps<'input'>, 'value'>
React.ComponentProps<'input'>
ComboboxLikeRenderOptionInput<ComboboxItem<Value>>
ScrollAreaProps
MantineColor
HTMLInputElement
InputLabelStylesNames
InputDescriptionStylesNames
InputErrorStylesNames
InputSuccessStylesNames
ComboboxLikeStylesNames
React.JSX.Element