Unstyled Select
The Select components let you create lists of options for users to choose from.
Introduction
A select is a UI element that gives users a list of options to choose from.
Base UI offers a components to replace the native HTML <select>
tag: Unstyled Select.
It also includes Unstyled Option for creating the options on the list, and Unstyled Option Group for grouping those options.
Features
- 🦍 Can be used as a controlled or uncontrolled component
- 🧬 Accepts custom elements and non-string values for options
- 🗃️ Options can be grouped and nested
Components
Usage
After installation, you can start building with this component collection using the following basic elements:
import SelectUnstyled from '@mui/base/SelectUnstyled';
import OptionUnstyled from '@mui/base/OptionUnstyled';
export default function MyApp() {
return (
<SelectUnstyled>
<OptionUnstyled>{/* option one */}</OptionUnstyled>
<OptionUnstyled>{/* option two */}</OptionUnstyled>
</SelectUnstyled>
);
}
Basics
The following demo shows how to create and style a Select component.
Form submission
The value(s) chosen in the Unstyled Select can be posted to a server using a standard HTML form.
When the name
prop is set, the Select will render a hidden input with the selected value.
Note how the second Select in the demo above renders a hidden input with the name provided as a prop.
You can customize the value of this hidden input. See the Object values section to learn how to do it.
TypeScript caveat
Unstyled Select accepts generic props.
Due to TypeScript limitations, this may cause unexpected behavior when wrapping the component in forwardRef
(or other higher-order components).
In such cases, the generic argument will be defaulted to unknown
and type suggestions will be incomplete.
To avoid this, you can manually cast the resulting component to the correct type:
const CustomSelect = React.forwardRef(function CustomSelect<TValue>(
props: SelectUnstyledProps<TValue>,
ref: React.ForwardedRef<HTMLUListElement>,
) {
// ...your code here...
return <SelectUnstyled {...props} ref={ref} />;
}) as <TValue>(
props: SelectUnstyledProps<TValue> & React.RefAttributes<HTMLUListElement>,
) => JSX.Element;
For the sake of brevity, the rest of the demos throughout this doc will not use forwardRef
.
Multi-select
The Unstyled Select component lets your users select multiple options from the list.
Set the multiple
prop to turn on the multi-selection mode.
Anatomy
The Select component is composed of a root <button>
along with a <div>
that houses a <ul>
within an Unstyled Popper.
Unstyled Option renders as an <li>
:
<button class="MuiSelectUnstyled-root" type="button">Open</button>
<div class="MuiSelectUnstyled-popper">
<ul class="MuiSelectUnstyled-listbox">
<li class="MuiOptionUnstyled-root">Option one</li>
<li class="MuiOptionUnstyled-root">Option two</li>
</ul>
</div>
Slot props
Use the component
prop to override the root slot with a custom element:
<SelectUnstyled component="div" />
Use the slots
prop to override any interior slots in addition to the root:
<SelectUnstyled slots={{ root: 'div', listbox: 'ol' }} />
Use the slotProps
prop to pass custom props to internal slots.
The following code snippet applies a CSS class called my-listbox
to the listbox slot:
<SelectUnstyled slotProps={{ listbox: { className: 'my-listbox' } }} />
Hooks
import useSelect from '@mui/base/useSelect';
The useSelect
hook lets you apply the functionality of a select to a fully custom component.
It returns props to be placed on the custom component, along with fields representing the component's internal state.
Hooks do not support slot props, but they do support customization props.
The following example shows a select built with a hook. Note how this component does not include any built-in classes. The resulting HTML is much smaller compared to the unstyled component version, as the class names are not applied.
- Red
- Green
- Blue
Customization
Controlled select
Unstyled Select can be used as an uncontrolled or controlled component:
Selected value: 10
Selected character:
{ "name": "Frodo", "race": "Hobbit" }
If you use a Select with object values in a form and post the form contents to a server, the selected value will be converted to JSON.
You can change this behavior with the help of the getSerializedValue
prop.
Selected value appearance
You can customize the appearance of the selected value display by providing a function to the renderValue
prop.
The element returned by this function will be rendered inside the select's button.
Option appearance
Options don't have to be plain strings. You can include custom elements to be rendered inside the listbox.
Grouping options
Options can be grouped, similarly to how the native <select>
element works.
Unlike the native <select>
, groups can be nested.
The following demo shows how to group options with the Unstyled Option Group component:
OptionGroupUnstyled API
Import
import OptionGroupUnstyled from '@mui/base/OptionGroupUnstyled';
// or
import { OptionGroupUnstyled } from '@mui/base';
Props
Props of the native component are also available.
Name | Type | Default | Description |
---|---|---|---|
component | elementType | The component used for the root node. Either a string to use a HTML element or a component. | |
disabled | bool | false | If true all the options in the group will be disabled. |
label | node | The human-readable description of the group. | |
slotProps | { label?: func | object, list?: func | object, root?: func | object } | {} | The props used for each slot inside the Input. |
slots | { label?: elementType, list?: elementType, root?: elementType } | {} | The components used for each slot inside the OptionGroupUnstyled. Either a string to use a HTML element or a component. See Slots API below for more details. |
The
ref
is forwarded to the root element.Slots
To learn how to customize the slot, check out the Overriding component structure guide.
Name | Default class | Default HTML tag | Description |
---|---|---|---|
root | .MuiOptionGroup-root | 'li' | The component that renders the root. |
label | .MuiOptionGroup-label | 'span' | The component that renders the label. |
list | .MuiOptionGroup-list | 'ul' | The component that renders the list. |
You can override the style of the component using one of these customization options:
- With a global class name.
- With a rule name as part of the component's
styleOverrides
property in a custom theme.
CSS classes
These class names are useful for styling with CSS. They are applied to the root slot when specific states are triggered.
Global class | Description |
---|---|
.Mui-disabled STATE | State class applied to the root `li` element if disabled={true} . |
OptionUnstyled API
Import
import OptionUnstyled from '@mui/base/OptionUnstyled';
// or
import { OptionUnstyled } from '@mui/base';
Props
Props of the native component are also available.
Name | Type | Default | Description |
---|---|---|---|
value* | any | The value of the option. | |
component | elementType | The component used for the root node. Either a string to use a HTML element or a component. | |
disabled | bool | false | If true , the option will be disabled. |
label | string | A text representation of the option's content. Used for keyboard text navigation matching. | |
slotProps | { root?: func | object } | {} | The props used for each slot inside the OptionUnstyled. |
slots | { root?: elementType } | {} | The components used for each slot inside the OptionUnstyled. Either a string to use a HTML element or a component. See Slots API below for more details. |
The
ref
is forwarded to the root element.Slots
To learn how to customize the slot, check out the Overriding component structure guide.
Name | Default class | Default HTML tag | Description |
---|---|---|---|
root | .MuiOption-root | 'li' | The component that renders the root. |
You can override the style of the component using one of these customization options:
- With a global class name.
- With a rule name as part of the component's
styleOverrides
property in a custom theme.
CSS classes
These class names are useful for styling with CSS. They are applied to the root slot when specific states are triggered.
Global class | Description |
---|---|
.Mui-disabled STATE | State class applied to the root `li` element if disabled={true} . |
.Mui-selected STATE | State class applied to the root `li` element if selected={true} . |
.MuiOption-highlighted | State class applied to the root `li` element if highlighted={true} . |
SelectUnstyled API
Import
import SelectUnstyled from '@mui/base/SelectUnstyled';
// or
import { SelectUnstyled } from '@mui/base';
Props
Props of the native component are also available.
Name | Type | Default | Description |
---|---|---|---|
autoFocus | bool | false | If true , the select element is focused during the first mount |
component | elementType | The component used for the root node. Either a string to use a HTML element or a component. | |
defaultListboxOpen | bool | false | If true , the select will be initially open. |
defaultValue | any | The default selected value. Use when the component is not controlled. | |
disabled | bool | false | If true , the select is disabled. |
getSerializedValue | func | A function to convert the currently selected value to a string. Used to set a value of a hidden input associated with the select, so that the selected value can be posted with a form. | |
listboxId | string | id attribute of the listbox element. Also used to derive the id attributes of options. | |
listboxOpen | bool | undefined | Controls the open state of the select's listbox. |
multiple | bool | false | If true , selecting multiple values is allowed. |
name | string | Name of the element. For example used by the server to identify the fields in form submits. If the name is provided, the component will render a hidden input element that can be submitted to a server. | |
onChange | func | Callback fired when an option is selected. | |
onListboxOpenChange | func | Callback fired when the component requests to be opened. Use in controlled mode (see listboxOpen). | |
optionStringifier | func | defaultOptionStringifier | A function used to convert the option label to a string. It's useful when labels are elements and need to be converted to plain text to enable navigation using character keys on a keyboard. |
renderValue | func | Function that customizes the rendering of the selected value. | |
slotProps | { listbox?: func | object, popper?: func | object, root?: func | object } | {} | The props used for each slot inside the Input. |
slots | { listbox?: elementType, popper?: elementType, root?: elementType } | {} | The components used for each slot inside the Select. Either a string to use a HTML element or a component. See Slots API below for more details. |
value | any | The selected value. Set to null to deselect all options. |
The
ref
is forwarded to the root element.Slots
To learn how to customize the slot, check out the Overriding component structure guide.
Name | Default class | Default HTML tag | Description |
---|---|---|---|
root | .MuiSelect-root | 'button' | The component that renders the root. |
listbox | .MuiSelect-listbox | 'ul' | The component that renders the listbox. |
popper | .MuiSelect-popper | PopperUnstyled | The component that renders the popper. |
You can override the style of the component using one of these customization options:
- With a global class name.
- With a rule name as part of the component's
styleOverrides
property in a custom theme.
CSS classes
These class names are useful for styling with CSS. They are applied to the root slot when specific states are triggered.
Global class | Description |
---|---|
.Mui-active STATE | State class applied to the root `button` element if active={true} . |
.Mui-disabled STATE | State class applied to the root `button` element and the listbox 'ul' element if disabled={true} . |
.Mui-expanded STATE | State class applied to the root `button` element if expanded={true} . |
.Mui-focusVisible STATE | State class applied to the root `button` element if focusVisible={true} . |
useOption API
Import
import useOption from '@mui/base/useOption';
// or
import { useOption } from '@mui/base';
Parameters
Name | Type | Description |
---|---|---|
disabled* | boolean | |
value* | Value | |
optionRef | React.Ref<HTMLElement> |
Return value
Name | Type | Description |
---|---|---|
getRootProps | <Other extends EventHandlers>(otherHandlers?: Other) => UseOptionRootSlotProps<Other> | |
highlighted | boolean | |
index | number | |
selected | boolean |
useSelect API
Import
import useSelect from '@mui/base/useSelect';
// or
import { useSelect } from '@mui/base';
Parameters
Name | Type | Description |
---|
Return value
Name | Type | Description |
---|