UNPKG

@mui/material

Version:

Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box.

1,399 lines (1,213 loc) • 43.5 kB
--- productId: material-ui title: React Select component components: Select, NativeSelect githubLabel: 'scope: select' materialDesign: https://m2.material.io/components/menus#exposed-dropdown-menu waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/combobox/examples/combobox-select-only/ githubSource: packages/mui-material/src/Select --- # Select Select components are used for collecting user provided information from a list of options. ## Basic select Menus are positioned under their emitting elements, unless they are close to the bottom of the viewport. ```tsx 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> ); } ``` ## Advanced features The Select component is meant to be interchangeable with a native `<select>` element. If you are looking for more advanced features, like combobox, multiselect, autocomplete, async or creatable support, head to the [`Autocomplete` component](/material-ui/react-autocomplete/). It's meant to be an improved version of the "react-select" and "downshift" packages. ## Props The Select component is implemented as a custom `<input>` element of the [InputBase](/material-ui/api/input-base/). It extends the [text field components](/material-ui/react-text-field/) subcomponents, either the [OutlinedInput](/material-ui/api/outlined-input/), [Input](/material-ui/api/input/), or [FilledInput](/material-ui/api/filled-input/), depending on the variant selected. It shares the same styles and many of the same props. Refer to the respective component's API page for details. :::warning Unlike input components, the `placeholder` prop is not available in Select. To add a placeholder, refer to the [placeholder](#placeholder) section below. ::: ### Variants ```tsx import * as React from 'react'; 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 SelectVariants() { const [age, setAge] = React.useState(''); const handleChange = (event: SelectChangeEvent) => { setAge(event.target.value); }; return ( <div> <FormControl variant="outlined" sx={{ m: 1, minWidth: 120 }}> <InputLabel id="demo-simple-select-outlined-label">Age</InputLabel> <Select labelId="demo-simple-select-outlined-label" id="demo-simple-select-outlined" value={age} onChange={handleChange} label="Age" > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> <FormControl variant="standard" sx={{ m: 1, minWidth: 120 }}> <InputLabel id="demo-simple-select-standard-label">Age</InputLabel> <Select labelId="demo-simple-select-standard-label" id="demo-simple-select-standard" value={age} onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> <FormControl variant="filled" sx={{ m: 1, minWidth: 120 }}> <InputLabel id="demo-simple-select-filled-label">Age</InputLabel> <Select labelId="demo-simple-select-filled-label" id="demo-simple-select-filled" value={age} onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </div> ); } ``` :::warning Note that when using FormControl with the outlined variant of the Select, you need to provide a label in two places: in the InputLabel component and in the `label` prop of the Select component (see the above demo). This is needed for the label floating animation to work correctly. ::: ### Labels and helper text Select always needs an accessible name. This can come from an associated visible label, such as an `InputLabel` linked to the `Select` with `labelId` or from adding an `aria-label` prop to the input element props (`inputProps`). If more information is needed, provide a helper text element and link it to the `Select` using `aria-describedby`. ```tsx import * as React from 'react'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import FormHelperText from '@mui/material/FormHelperText'; import FormControl from '@mui/material/FormControl'; import Select, { SelectChangeEvent } from '@mui/material/Select'; export default function SelectLabels() { const id = React.useId(); const noLabelId = React.useId(); const [age, setAge] = React.useState(''); const handleChange = (event: SelectChangeEvent) => { setAge(event.target.value); }; return ( <div> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel id={`${id}-label`}>Age</InputLabel> <Select aria-describedby={`${id}-helper-text`} labelId={`${id}-label`} id={id} value={age} label="Age" onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> <FormHelperText id={`${id}-helper-text`}> Visible label and helper text </FormHelperText> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <Select aria-describedby={`${noLabelId}-helper-text`} value={age} onChange={handleChange} displayEmpty inputProps={{ 'aria-label': 'Age' }} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> <FormHelperText id={`${noLabelId}-helper-text`}> aria-label and helper text </FormHelperText> </FormControl> </div> ); } ``` ### Auto width ```tsx import * as React from 'react'; 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 SelectAutoWidth() { const [age, setAge] = React.useState(''); const handleChange = (event: SelectChangeEvent) => { setAge(event.target.value); }; return ( <div> <FormControl sx={{ m: 1, minWidth: 80 }}> <InputLabel id="demo-simple-select-autowidth-label">Age</InputLabel> <Select labelId="demo-simple-select-autowidth-label" id="demo-simple-select-autowidth" value={age} onChange={handleChange} autoWidth label="Age" > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={21}>Twenty one</MenuItem> <MenuItem value={22}>Twenty one and a half</MenuItem> </Select> </FormControl> </div> ); } ``` ### Small Size ```tsx import * as React from 'react'; 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 SelectSmall() { const [age, setAge] = React.useState(''); const handleChange = (event: SelectChangeEvent) => { setAge(event.target.value); }; return ( <FormControl sx={{ m: 1, minWidth: 120 }} size="small"> <InputLabel id="demo-select-small-label">Age</InputLabel> <Select labelId="demo-select-small-label" id="demo-select-small" value={age} label="Age" onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> ); } ``` ### Other props ```tsx import * as React from 'react'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import FormHelperText from '@mui/material/FormHelperText'; import FormControl from '@mui/material/FormControl'; import Select, { SelectChangeEvent } from '@mui/material/Select'; export default function SelectOtherProps() { const [age, setAge] = React.useState(''); const handleChange = (event: SelectChangeEvent) => { setAge(event.target.value); }; return ( <div> <FormControl sx={{ m: 1, minWidth: 120 }} disabled> <InputLabel id="demo-simple-select-disabled-label">Age</InputLabel> <Select labelId="demo-simple-select-disabled-label" id="demo-simple-select-disabled" value={age} label="Age" onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> <FormHelperText>Disabled</FormHelperText> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }} error> <InputLabel id="demo-simple-select-error-label">Age</InputLabel> <Select labelId="demo-simple-select-error-label" id="demo-simple-select-error" value={age} label="Age" onChange={handleChange} renderValue={(value) => `⚠️ - ${value}`} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> <FormHelperText>Error</FormHelperText> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel id="demo-simple-select-readonly-label">Age</InputLabel> <Select labelId="demo-simple-select-readonly-label" id="demo-simple-select-readonly" value={age} label="Age" onChange={handleChange} inputProps={{ readOnly: true }} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> <FormHelperText>Read only</FormHelperText> </FormControl> <FormControl required sx={{ m: 1, minWidth: 120 }}> <InputLabel id="demo-simple-select-required-label">Age</InputLabel> <Select labelId="demo-simple-select-required-label" id="demo-simple-select-required" value={age} label="Age *" onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> <FormHelperText>Required</FormHelperText> </FormControl> </div> ); } ``` ## Native select As the user experience can be improved on mobile using the native select of the platform, we allow such pattern. ```tsx import * as React from 'react'; import Box from '@mui/material/Box'; import InputLabel from '@mui/material/InputLabel'; import FormControl from '@mui/material/FormControl'; import NativeSelect from '@mui/material/NativeSelect'; export default function NativeSelectDemo() { const id = React.useId(); return ( <Box sx={{ minWidth: 120 }}> <FormControl fullWidth> <InputLabel variant="standard" htmlFor={`${id}-select`}> Age </InputLabel> <NativeSelect defaultValue={30} inputProps={{ name: 'age', id: `${id}-select`, }} > <option value={10}>Ten</option> <option value={20}>Twenty</option> <option value={30}>Thirty</option> </NativeSelect> </FormControl> </Box> ); } ``` ## TextField The `TextField` wrapper component is a complete form control including a label, input and help text. You can find an example with the select mode [in this section](/material-ui/react-text-field/#select). ## Customization Here are some examples of customizing the component. You can learn more about this in the [overrides documentation page](/material-ui/customization/how-to-customize/). The first step is to style the `InputBase` component. Once it's styled, you can either use it directly as a text field or provide it to the select `input` prop to have a `select` field. Notice that the `"standard"` variant is easier to customize, since it does not wrap the contents in a `fieldset`/`legend` markup. ```tsx import * as React from 'react'; import { styled } from '@mui/material/styles'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import FormControl from '@mui/material/FormControl'; import Select from '@mui/material/Select'; import NativeSelect from '@mui/material/NativeSelect'; import InputBase from '@mui/material/InputBase'; const BootstrapInput = styled(InputBase)(({ theme }) => ({ 'label + &': { marginTop: theme.spacing(3), }, '& .MuiInputBase-input': { borderRadius: 4, position: 'relative', backgroundColor: (theme.vars ?? theme).palette.background.paper, border: '1px solid #ced4da', fontSize: 16, padding: '10px 26px 10px 12px', transition: theme.transitions.create(['border-color', 'box-shadow']), // Use the system font instead of the default Roboto font. fontFamily: [ '-apple-system', 'BlinkMacSystemFont', '"Segoe UI"', 'Roboto', '"Helvetica Neue"', 'Arial', 'sans-serif', '"Apple Color Emoji"', '"Segoe UI Emoji"', '"Segoe UI Symbol"', ].join(','), '&:focus': { borderRadius: 4, borderColor: '#80bdff', boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)', }, }, })); export default function CustomizedSelects() { const textboxId = React.useId(); const selectId = React.useId(); const nativeId = React.useId(); const [age, setAge] = React.useState(''); const handleChange = (event: { target: { value: string } }) => { setAge(event.target.value); }; return ( <div> <FormControl sx={{ m: 1 }} variant="standard"> <InputLabel htmlFor={`${textboxId}-input`}>Age</InputLabel> <BootstrapInput id={`${textboxId}-input`} /> </FormControl> <FormControl sx={{ m: 1 }} variant="standard"> <InputLabel id={`${selectId}-label`}>Age</InputLabel> <Select labelId={`${selectId}-label`} id={`${selectId}-select`} value={age} onChange={handleChange} input={<BootstrapInput />} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> <FormControl sx={{ m: 1 }} variant="standard"> <InputLabel htmlFor={`${nativeId}-select`}>Age</InputLabel> <NativeSelect id={`${nativeId}-select`} value={age} onChange={handleChange} input={<BootstrapInput />} > <option aria-label="None" value="" /> <option value={10}>Ten</option> <option value={20}>Twenty</option> <option value={30}>Thirty</option> </NativeSelect> </FormControl> </div> ); } ``` 🎨 If you are looking for inspiration, you can check [MUI Treasury's customization examples](https://mui-treasury.com/primitive/select). ## Multiple select The `Select` component can handle multiple selections. It's enabled with the `multiple` prop. Like with the single selection, you can pull out the new value by accessing `event.target.value` in the `onChange` callback. It's always an array. ### Default ```tsx import * as React from 'react'; import { Theme, useTheme } from '@mui/material/styles'; import OutlinedInput from '@mui/material/OutlinedInput'; 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'; const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { slotProps: { paper: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }, }; const names = [ 'Oliver Hansen', 'Van Henry', 'April Tucker', 'Ralph Hubbard', 'Omar Alexander', 'Carlos Abbott', 'Miriam Wagner', 'Bradley Wilkerson', 'Virginia Andrews', 'Kelly Snyder', ]; function getStyles(name: string, personName: string[], theme: Theme) { return { fontWeight: personName.includes(name) ? theme.typography.fontWeightMedium : theme.typography.fontWeightRegular, }; } export default function MultipleSelect() { const theme = useTheme(); const [personName, setPersonName] = React.useState<string[]>([]); const handleChange = (event: SelectChangeEvent<typeof personName>) => { const { target: { value }, } = event; setPersonName( // On autofill we get a stringified value. typeof value === 'string' ? value.split(',') : value, ); }; return ( <div> <FormControl sx={{ m: 1, width: 300 }}> <InputLabel id="demo-multiple-name-label">Name</InputLabel> <Select labelId="demo-multiple-name-label" id="demo-multiple-name" multiple value={personName} onChange={handleChange} input={<OutlinedInput label="Name" />} MenuProps={MenuProps} > {names.map((name) => ( <MenuItem key={name} value={name} style={getStyles(name, personName, theme)} > {name} </MenuItem> ))} </Select> </FormControl> </div> ); } ``` ### Selection indicators This example demonstrates how icons are used to indicate the selection state of each item in the listbox. ```tsx import * as React from 'react'; import OutlinedInput from '@mui/material/OutlinedInput'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import FormControl from '@mui/material/FormControl'; import ListItemText from '@mui/material/ListItemText'; import Select, { SelectChangeEvent } from '@mui/material/Select'; import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; import CheckBoxIcon from '@mui/icons-material/CheckBox'; const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { slotProps: { paper: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }, }; const names = [ 'Oliver Hansen', 'Van Henry', 'April Tucker', 'Ralph Hubbard', 'Omar Alexander', 'Carlos Abbott', 'Miriam Wagner', 'Bradley Wilkerson', 'Virginia Andrews', 'Kelly Snyder', ]; export default function MultipleSelectCheckmarks() { const [personName, setPersonName] = React.useState<string[]>([]); const handleChange = (event: SelectChangeEvent<typeof personName>) => { const { target: { value }, } = event; setPersonName( // On autofill we get a stringified value. typeof value === 'string' ? value.split(',') : value, ); }; return ( <div> <FormControl sx={{ m: 1, width: 300 }}> <InputLabel id="demo-multiple-checkbox-label">Tag</InputLabel> <Select labelId="demo-multiple-checkbox-label" id="demo-multiple-checkbox" multiple value={personName} onChange={handleChange} input={<OutlinedInput label="Tag" />} renderValue={(selected) => selected.join(', ')} MenuProps={MenuProps} > {names.map((name) => { const selected = personName.includes(name); const SelectionIcon = selected ? CheckBoxIcon : CheckBoxOutlineBlankIcon; return ( <MenuItem key={name} value={name}> <SelectionIcon fontSize="small" style={{ marginRight: 8, padding: 9, boxSizing: 'content-box' }} /> <ListItemText primary={name} /> </MenuItem> ); })} </Select> </FormControl> </div> ); } ``` ### Chip ```tsx import * as React from 'react'; import { Theme, useTheme } from '@mui/material/styles'; import Box from '@mui/material/Box'; import OutlinedInput from '@mui/material/OutlinedInput'; 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'; import Chip from '@mui/material/Chip'; const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { slotProps: { paper: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }, }; const names = [ 'Oliver Hansen', 'Van Henry', 'April Tucker', 'Ralph Hubbard', 'Omar Alexander', 'Carlos Abbott', 'Miriam Wagner', 'Bradley Wilkerson', 'Virginia Andrews', 'Kelly Snyder', ]; function getStyles(name: string, personName: readonly string[], theme: Theme) { return { fontWeight: personName.includes(name) ? theme.typography.fontWeightMedium : theme.typography.fontWeightRegular, }; } export default function MultipleSelectChip() { const theme = useTheme(); const [personName, setPersonName] = React.useState<string[]>([]); const handleChange = (event: SelectChangeEvent<typeof personName>) => { const { target: { value }, } = event; setPersonName( // On autofill we get a stringified value. typeof value === 'string' ? value.split(',') : value, ); }; return ( <div> <FormControl sx={{ m: 1, width: 300 }}> <InputLabel id="demo-multiple-chip-label">Chip</InputLabel> <Select labelId="demo-multiple-chip-label" id="demo-multiple-chip" multiple value={personName} onChange={handleChange} input={<OutlinedInput id="select-multiple-chip" label="Chip" />} renderValue={(selected) => ( <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 0.5 }}> {selected.map((value) => ( <Chip key={value} label={value} /> ))} </Box> )} MenuProps={MenuProps} > {names.map((name) => ( <MenuItem key={name} value={name} style={getStyles(name, personName, theme)} > {name} </MenuItem> ))} </Select> </FormControl> </div> ); } ``` ### Placeholder ```tsx import * as React from 'react'; import { Theme, useTheme } from '@mui/material/styles'; import OutlinedInput from '@mui/material/OutlinedInput'; import MenuItem from '@mui/material/MenuItem'; import FormControl from '@mui/material/FormControl'; import Select, { SelectChangeEvent } from '@mui/material/Select'; const ITEM_HEIGHT = 48; const ITEM_PADDING_TOP = 8; const MenuProps = { slotProps: { paper: { style: { maxHeight: ITEM_HEIGHT * 4.5 + ITEM_PADDING_TOP, width: 250, }, }, }, }; const names = [ 'Oliver Hansen', 'Van Henry', 'April Tucker', 'Ralph Hubbard', 'Omar Alexander', 'Carlos Abbott', 'Miriam Wagner', 'Bradley Wilkerson', 'Virginia Andrews', 'Kelly Snyder', ]; function getStyles(name: string, personName: readonly string[], theme: Theme) { return { fontWeight: personName.includes(name) ? theme.typography.fontWeightMedium : theme.typography.fontWeightRegular, }; } export default function MultipleSelectPlaceholder() { const theme = useTheme(); const [personName, setPersonName] = React.useState<string[]>([]); const handleChange = (event: SelectChangeEvent<typeof personName>) => { const { target: { value }, } = event; setPersonName( // On autofill we get a stringified value. typeof value === 'string' ? value.split(',') : value, ); }; return ( <div> <FormControl sx={{ m: 1, width: 300, mt: 3 }}> <Select multiple displayEmpty value={personName} onChange={handleChange} input={<OutlinedInput />} renderValue={(selected) => { if (selected.length === 0) { return <em>Placeholder</em>; } return selected.join(', '); }} MenuProps={MenuProps} inputProps={{ 'aria-label': 'Without label' }} > <MenuItem disabled value=""> <em>Placeholder</em> </MenuItem> {names.map((name) => ( <MenuItem key={name} value={name} style={getStyles(name, personName, theme)} > {name} </MenuItem> ))} </Select> </FormControl> </div> ); } ``` ### Native ```tsx import * as React from 'react'; import InputLabel from '@mui/material/InputLabel'; import FormControl from '@mui/material/FormControl'; import Select from '@mui/material/Select'; const names = [ 'Oliver Hansen', 'Van Henry', 'April Tucker', 'Ralph Hubbard', 'Omar Alexander', 'Carlos Abbott', 'Miriam Wagner', 'Bradley Wilkerson', 'Virginia Andrews', 'Kelly Snyder', ]; export default function MultipleSelectNative() { const id = React.useId(); const [personName, setPersonName] = React.useState<string[]>([]); const handleChangeMultiple = (event: React.ChangeEvent<HTMLSelectElement>) => { const { options } = event.target; const value: string[] = []; for (let i = 0, l = options.length; i < l; i += 1) { if (options[i].selected) { value.push(options[i].value); } } setPersonName(value); }; return ( <div> <FormControl sx={{ m: 1, minWidth: 120, maxWidth: 300 }}> <InputLabel shrink htmlFor={`${id}-select`}> Native </InputLabel> <Select<string[]> multiple native value={personName} // @ts-ignore Typings are not considering `native` onChange={handleChangeMultiple} label="Native" inputProps={{ id: `${id}-select`, }} > {names.map((name) => ( <option key={name} value={name}> {name} </option> ))} </Select> </FormControl> </div> ); } ``` ## Controlling the open state You can control the open state of the select with the `open` prop. Alternatively, it is also possible to set the initial (uncontrolled) open state of the component with the `defaultOpen` prop. :::info - A component is **controlled** when it's managed by its parent using props. - A component is **uncontrolled** when it's managed by its own local state. Learn more about controlled and uncontrolled components in the [React documentation](https://react.dev/learn/sharing-state-between-components#controlled-and-uncontrolled-components). ::: ```tsx import * as React from 'react'; 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'; import Button from '@mui/material/Button'; export default function ControlledOpenSelect() { const [age, setAge] = React.useState<string | number>(''); const [open, setOpen] = React.useState(false); const handleChange = (event: SelectChangeEvent<typeof age>) => { setAge(event.target.value); }; const handleClose = () => { setOpen(false); }; const handleOpen = () => { setOpen(true); }; return ( <div> <Button sx={{ display: 'block', mt: 2 }} onClick={handleOpen}> Open the select </Button> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel id="demo-controlled-open-select-label">Age</InputLabel> <Select labelId="demo-controlled-open-select-label" id="demo-controlled-open-select" open={open} onClose={handleClose} onOpen={handleOpen} value={age} label="Age" onChange={handleChange} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </div> ); } ``` ## With a dialog While it's discouraged by the Material Design guidelines, you can use a select inside a dialog. ```tsx import * as React from 'react'; import Box from '@mui/material/Box'; import Button from '@mui/material/Button'; import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; import InputLabel from '@mui/material/InputLabel'; import OutlinedInput from '@mui/material/OutlinedInput'; import MenuItem from '@mui/material/MenuItem'; import FormControl from '@mui/material/FormControl'; import Select, { SelectChangeEvent } from '@mui/material/Select'; export default function DialogSelect() { const nativeId = React.useId(); const selectId = React.useId(); const [open, setOpen] = React.useState(false); const [age, setAge] = React.useState<number | string>(''); const handleChange = (event: SelectChangeEvent<typeof age>) => { setAge(Number(event.target.value) || ''); }; const handleClickOpen = () => { setOpen(true); }; const handleDialogClose = ( _event: React.SyntheticEvent<unknown>, reason: string, ) => { if (!['backdropClick', 'escapeKeyDown'].includes(reason)) { setOpen(false); } }; const handleActionButtonClick = () => { setOpen(false); }; return ( <div> <Button onClick={handleClickOpen}>Open select dialog</Button> <Dialog open={open} onClose={handleDialogClose}> <DialogTitle>Fill the form</DialogTitle> <DialogContent> <Box component="form" sx={{ display: 'flex', flexWrap: 'wrap' }}> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor={`${nativeId}-select`}>Age</InputLabel> <Select native value={age} onChange={handleChange} input={<OutlinedInput label="Age" id={`${nativeId}-select`} />} > <option aria-label="None" value="" /> <option value={10}>Ten</option> <option value={20}>Twenty</option> <option value={30}>Thirty</option> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel id={`${selectId}-label`}>Age</InputLabel> <Select labelId={`${selectId}-label`} id={`${selectId}-select`} value={age} onChange={handleChange} input={<OutlinedInput label="Age" />} > <MenuItem value=""> <em>None</em> </MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl> </Box> </DialogContent> <DialogActions> <Button onClick={handleActionButtonClick}>Cancel</Button> <Button onClick={handleActionButtonClick}>Ok</Button> </DialogActions> </Dialog> </div> ); } ``` ## Grouping Display categories with the `ListSubheader` component or the native `<optgroup>` element. ```tsx import * as React from 'react'; import InputLabel from '@mui/material/InputLabel'; import MenuItem from '@mui/material/MenuItem'; import ListSubheader from '@mui/material/ListSubheader'; import FormControl from '@mui/material/FormControl'; import Select from '@mui/material/Select'; export default function GroupedSelect() { const nativeId = React.useId(); const id = React.useId(); return ( <div> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel htmlFor={`${nativeId}-select`}>Grouping</InputLabel> <Select native defaultValue="" id={`${nativeId}-select`} label="Grouping"> <option aria-label="None" value="" /> <optgroup label="Category 1"> <option value={1}>Option 1</option> <option value={2}>Option 2</option> </optgroup> <optgroup label="Category 2"> <option value={3}>Option 3</option> <option value={4}>Option 4</option> </optgroup> </Select> </FormControl> <FormControl sx={{ m: 1, minWidth: 120 }}> <InputLabel id={`${id}-label`}>Grouping</InputLabel> <Select defaultValue="" id={`${id}-select`} label="Grouping" SelectDisplayProps={{ 'aria-labelledby': `${id}-label`, }} > <MenuItem value=""> <em>None</em> </MenuItem> <ListSubheader>Category 1</ListSubheader> <MenuItem value={1}>Option 1</MenuItem> <MenuItem value={2}>Option 2</MenuItem> <ListSubheader>Category 2</ListSubheader> <MenuItem value={3}>Option 3</MenuItem> <MenuItem value={4}>Option 4</MenuItem> </Select> </FormControl> </div> ); } ``` ## Accessibility To properly label your `Select` input you need an extra element with an `id` that contains a label. That `id` needs to match the `labelId` of the `Select`, for example: ```jsx <InputLabel id="label">Age</InputLabel> <Select labelId="label" id="select" value="20"> <MenuItem value="10">Ten</MenuItem> <MenuItem value="20">Twenty</MenuItem> </Select> ``` Alternatively a `TextField` with an `id` and `label` creates the proper markup and ids for you: ```jsx <TextField id="select" label="Age" value="20" select> <MenuItem value="10">Ten</MenuItem> <MenuItem value="20">Twenty</MenuItem> </TextField> ``` For a [native select](#native-select), you should mention a label by giving the value of the `id` attribute of the select element to the `InputLabel`'s `htmlFor` attribute: ```jsx <InputLabel htmlFor="select">Age</InputLabel> <NativeSelect id="select"> <option value="10">Ten</option> <option value="20">Twenty</option> </NativeSelect> ``` # NativeSelect API ## Demos For examples and details on the usage of this React component, visit the component demo pages: - [Select](https://mui.com/material-ui/react-select/) ## Import ```jsx import NativeSelect from '@mui/material/NativeSelect'; // or import { NativeSelect } from '@mui/material'; ``` ## Props | Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | children | `node` | - | No | | | classes | `object` | `{}` | No | Override or extend the styles applied to the component. | | IconComponent | `elementType` | `ArrowDropDownIcon` | No | | | input | `element` | `<Input />` | No | | | inputProps | `object` | - | No | | | onChange | `function(event: React.ChangeEvent<HTMLSelectElement>) => void` | - | No | | | sx | `Array<func \| object \| bool> \| func \| object` | - | No | The system prop that allows defining system overrides as well as additional CSS styles. | | value | `any` | - | No | | | variant | `'filled' \| 'outlined' \| 'standard'` | - | No | | > **Note**: The `ref` is forwarded to the root element (HTMLDivElement). > Any other props supplied will be provided to the root element ([Input](https://mui.com/material-ui/api/input/)). ## Inheritance While not explicitly documented above, the props of the [Input](https://mui.com/material-ui/api/input/) component are also available on NativeSelect. ## Theme default props You can use `MuiNativeSelect` to change the default props of this component with the theme. ## CSS ### Rule name | Global class | Rule name | Description | |--------------|-----------|-------------| | `.Mui-disabled` | - | State class applied to the select component `disabled` class. | | `.Mui-error` | - | State class applied to the select component `error` class. | | - | filled | Styles applied to the select component if `variant="filled"`. | | - | icon | Styles applied to the icon component. | | - | iconFilled | Styles applied to the icon component if `variant="filled"`. | | - | iconOpen | Styles applied to the icon component if the popup is open. | | - | iconOutlined | Styles applied to the icon component if `variant="outlined"`. | | - | iconStandard | Styles applied to the icon component if `variant="standard"`. | | - | multiple | Styles applied to the select component if `multiple={true}`. | | - | nativeInput | Styles applied to the underlying native input component. | | - | outlined | Styles applied to the select component if `variant="outlined"`. | | - | root | Styles applied to the root element. | | - | select | Styles applied to the select component `select` class. | | - | standard | Styles applied to the select component if `variant="standard"`. | ## Source code If you did not find the information on this page, consider having a look at the implementation of the component for more detail. - [/packages/mui-material/src/NativeSelect/NativeSelect.js](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material/src/NativeSelect/NativeSelect.js) # Select API ## Demos For examples and details on the usage of this React component, visit the component demo pages: - [Select](https://mui.com/material-ui/react-select/) ## Import ```jsx import Select from '@mui/material/Select'; // or import { Select } from '@mui/material'; ``` ## Props | Name | Type | Default | Required | Description | |------|------|---------|----------|-------------| | autoWidth | `bool` | `false` | No | | | children | `node` | - | No | | | classes | `object` | `{}` | No | Override or extend the styles applied to the component. | | defaultOpen | `bool` | `false` | No | | | defaultValue | `any` | - | No | | | displayEmpty | `bool` | `false` | No | | | IconComponent | `elementType` | `ArrowDropDownIcon` | No | | | id | `string` | - | No | | | input | `element` | - | No | | | inputProps | `object` | - | No | | | label | `node` | - | No | | | labelId | `string` | - | No | | | MenuProps | `object` | - | No | | | multiple | `bool` | `false` | No | | | native | `bool` | `false` | No | | | onChange | `function(event: SelectChangeEvent<Value>, child?: object) => void` | - | No | | | onClose | `function(event: object) => void` | - | No | | | onOpen | `function(event: object) => void` | - | No | | | open | `bool` | - | No | | | renderValue | `function(value: any) => ReactNode` | - | No | | | SelectDisplayProps | `object` | - | No | | | sx | `Array<func \| object \| bool> \| func \| object` | - | No | The system prop that allows defining system overrides as well as additional CSS styles. | | value | `'' \| any` | - | No | | | variant | `'filled' \| 'outlined' \| 'standard'` | `'outlined'` | No | | > **Note**: The `ref` is forwarded to the root element (HTMLDivElement). > Any other props supplied will be provided to the root element ([OutlinedInput](https://mui.com/material-ui/api/outlined-input/)). ## Inheritance While not explicitly documented above, the props of the [OutlinedInput](https://mui.com/material-ui/api/outlined-input/) component are also available on Select. ## Theme default props You can use `MuiSelect` to change the default props of this component with the theme. ## CSS ### Rule name | Global class | Rule name | Description | |--------------|-----------|-------------| | `.Mui-disabled` | - | State class applied to the select component `disabled` class. | | `.Mui-error` | - | State class applied to the root element if `error={true}`. | | - | filled | Styles applied to the select component if `variant="filled"`. | | `.Mui-focused` | - | Styles applied to the select component if it is focused. | | - | icon | Styles applied to the icon component. | | - | iconOpen | Styles applied to the icon component if the popup is open. | | - | multiple | Styles applied to the select component if `multiple={true}`. | | - | nativeInput | Styles applied to the underlying native input component. | | - | outlined | Styles applied to the select component if `variant="outlined"`. | | - | root | Styles applied to the root element. | | - | select | Styles applied to the select component `select` class. | | - | standard | Styles applied to the select component if `variant="standard"`. | ## Source code If you did not find the information on this page, consider having a look at the implementation of the component for more detail. - [/packages/mui-material/src/Select/Select.js](https://github.com/mui/material-ui/tree/HEAD/packages/mui-material/src/Select/Select.js)