Skip to content
+

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's Select component replaces the native HTML <select> tag. It also includes the Option component for creating the options in the list, and Option Group for grouping those options.

Components

import { Select } from '@mui/base/Select';
import { Option } from '@mui/base/Option';

The following demo shows how to create and style a Select component with several Options:

Form submission

The value(s) chosen in the Select can be posted to a server using a standard HTML form.

Press Enter to start editing

You can customize the value of this hidden input—see the Object values section for details.

TypeScript caveat

Select's props are generic. 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: SelectProps<TValue>,
  ref: React.ForwardedRef<HTMLUListElement>,
) {
  // ...your code here...
  return <Select {...props} ref={ref} />;
}) as <TValue>(
  props: SelectProps<TValue> & React.RefAttributes<HTMLUListElement>,
) => JSX.Element;

For the sake of brevity, the rest of the demos throughout this doc will not use forwardRef.

Multiple selections

Set the multiple prop to let your users select multiple options from the list. In contrast with single-selection mode, the options popup doesn't close after an item is selected, which enables users to continue choosing more options.

Note that in multiple selection mode, the value prop (and defaultValue) is an array.

Controlled select

Select can be used as an uncontrolled or controlled component.

Selected value: 10

Use the value prop to set the value of the controlled Select. The uncontrolled component accepts the defaultValue that can be used to set the initial value. To deselect all values, pass null to the respective prop.

Object values

The Select component can be used with non-string values:

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.

Grouping options

import { OptionGroup } from '@mui/base/OptionGroup';

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 Option Group component:

Anatomy

The Select component is composed of a root <button> along with a <div> that houses a <ul> within a Popup. Option renders as an <li>, and Option Group renders a <ul> with an <li> that represents its label.

<button class="base-Select-root" type="button">Open</button>
<div class="base-Select-popup">
  <ul class="base-Select-listbox">
    <li class="base-Option-root">Option one</li>
    <li class="base-Option-root">Option two</li>
  </ul>
</div>

Custom structure

Use the slots prop to override the root or any other interior slot:

<Select 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:

<Select slotProps={{ listbox: { className: 'my-listbox' } }} />

Portals

By default, the Select's popup is rendered in a Portal and appended to the bottom of the DOM. To instead render the popup where the component is defined, override the disablePortal prop of the underlying Popup, as shown below:

<Select slotProps={{ popup: { disablePortal: true } }} />

Transitions

The Select component supports the Transitions API, so it's possible to animate the appearing and disappearing Listbox. To do this, override the Listbox slot of the Select and wrap it with a transition component (CssTransition, CssAnimation, or a custom-built one).

Usage with TypeScript

In TypeScript, you can specify the custom component type used in the slots.root as a generic parameter of the unstyled component. This way, you can safely provide the custom root's props directly on the component:

<Select<typeof CustomComponent> slots={{ root: CustomComponent }} customProp />

The same applies for props specific to custom primitive elements:

<Select<'button'> slots={{ root: 'button' }} onClick={() => {}} />

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 with its prebuilt component counterpart, because the class names are not applied.

Performance

The useOption hook listens to changes in a context that is set up by the parent Select component. This context changes every time an item is highlighted. Usually, it shouldn't be a problem, however, when your select has hundreds of options, you may notice it's not very responsive, as every option is rerendered whenever highlight changes.

To improve performance by preventing options from rendering unnecessarily, you can create a component that wraps the option. Inside this component, call useOptionContextStabilizer and create a ListContext with the value from the hook's result:

const StableOption = React.forwardRef(function StableOption<OptionValue>(
  props: OptionProps<OptionValue>,
  ref: React.ForwardedRef<Element>,
) {
  const { contextValue } = useOptionContextStabilizer(props.value);

  return (
    <ListContext.Provider value={contextValue}>
      <Option {...props} ref={ref} />
    </ListContext.Provider>
  );
});

The useOptionContextStabilizer hook ensures that the context value changes only when the state of the option is updated.

Customization

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.

Press Enter to start editing

Option appearance

Options don't have to be plain strings. You can include custom elements to be rendered inside the listbox.

Press Enter to start editing