Select

Select provides users with a floating element containing a list of options to choose from.

Give FeedbackWAI-ARIABundle Size

Introduction

index.tsx

Installation

Base UI components are all available as a single package.

npm install @base-ui-components/react

Once you have the package installed, import the component.

import { Select } from '@base-ui-components/react/select';

Anatomy

Selects are implemented using a collection of related components:

<Select.Root>
  <Select.Trigger>
    <Select.Value />
    <Select.Icon />
  </Select.Trigger>

  <Select.Backdrop />

  <Select.Positioner>
    <Select.ScrollUpArrow />

    <Select.Popup>
      <Select.Group>
        <Select.GroupLabel />
        <Select.Option>
          <Select.OptionText />
          <Select.OptionIndicator />
        </Select.Option>
      </Select.Group>
      <Select.Separator />
    </Select.Popup>

    <Select.ScrollDownArrow />

    <Select.Arrow />
  </Select.Positioner>
</Select.Root>

Default value

To set an initial value when uncontrolled, use defaultValue:

<Select.Root defaultValue="system">

Empty value

The select's value is empty (null) by default, which enables an empty Option to be initially selected when it has no value prop:

SelectEmpty.tsx

Controlled

To control the value with external state, specify the value and onValueChange props:

const [value, setValue] = React.useState('system');

return (
  <Select.Root value={value} onValueChange={setValue}>
    {/* subcomponents */}
  </Select.Root>
);

Option indicator

The Select.OptionIndicator subcomponent renders an indicator inside an option to indicate it's selected. By default, it renders a check icon, but this can be customized:

<Select.OptionIndicator>
  <MyCheckIcon />
</Select.OptionIndicator>

Grouped options

Select.Group can be used to group options together with a label. The Select.GroupLabel subcomponent renders the label:

<Select.Group>
  <Select.GroupLabel>Label</Select.GroupLabel>
  <Select.Option value="option1">Option 1</Select.Option>
  <Select.Option value="option2">Option 2</Select.Option>
</Select.Group>
SelectGroup.tsx

Align method

By default, the selected option inside the popup is aligned to the trigger element. This can be disabled with the alignOptionToTrigger prop:

<Select.Root alignOptionToTrigger={false}>

alignOptionToTrigger is always false on touch devices or touch input.

Scrolling is locked when alignOptionToTrigger is true to prevent unwanted scrolling of the background when expanding the popup, ensuring positioning remains correct.

SelectAlign.tsx

Scrollable popup

The select's height needs to be manually limited by its available space using CSS.

This can be achieved by using the --available-height CSS variable:

<Select.Popup className="SelectPopup">
.SelectPopup {
  max-height: var(--available-height);
}

Value component

The Select.Value subcomponent renders the selected value. This is the text content or label of Select.Option by default.

The placeholder prop can be used when the value is empty. During SSR, if a default value is specified as the selected option, the value isn't available until hydration:

<Select.Trigger>
  <Select.Value placeholder="Select value..." />
</Select.Trigger>

A function can be specified as a child to customize the rendering of the value:

<Select.Value>{(value) => value.toLowerCase()}</Select.Value>

Arrow

To add an arrow (caret or triangle) inside the select popup that points toward the center of the anchor element, use the Select.Arrow component:

This is not supported when alignOptionToTrigger is true.
<Select.Positioner>
  <Select.Popup />
  <Select.Arrow />
</Select.Positioner>

It automatically positions a wrapper element that can be styled or contain a custom SVG shape.

Animations

The select can animate when opening or closing with either:

CSS transitions

Here is an example of how to apply a symmetric scale and fade transition with the default conditionally-rendered behavior:

<Select.Popup className="SelectPopup">
  <Select.Option>Option 1</Select.Option>
</Select.Popup>
.SelectPopup {
  transform-origin: var(--transform-origin);
  transition-property: opacity, transform;
  transition-duration: 0.2s;
  /* Represents the final styles once exited */
  opacity: 0;
  transform: scale(0.9);
}

/* Represents the final styles once entered */
.SelectPopup[data-open] {
  opacity: 1;
  transform: scale(1);
}

/* Represents the initial styles when entering */
.SelectPopup[data-entering] {
  opacity: 0;
  transform: scale(0.9);
}

Styles need to be applied in three states:

In newer browsers, there is a feature called @starting-style which allows transitions to occur on open for conditionally-mounted components:

/* Base UI API - Polyfill */
.SelectPopup[data-entering] {
  opacity: 0;
  transform: scale(0.9);
}

/* Official Browser API - no Firefox support as of May 2024 */
@starting-style {
  .SelectPopup[data-open] {
    opacity: 0;
    transform: scale(0.9);
  }
}

CSS animations

CSS animations can also be used, requiring only two separate declarations:

@keyframes scale-in {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
}

@keyframes scale-out {
  to {
    opacity: 0;
    transform: scale(0.9);
  }
}

.SelectPopup {
  animation: scale-in 0.2s forwards;
}

.SelectPopup[data-exiting] {
  animation: scale-out 0.2s forwards;
}

JavaScript animations

The keepMounted prop lets an external library control the mounting, for example framer-motion's AnimatePresence component.

function App() {
  const [open, setOpen] = useState(false);
  return (
    <Select.Root open={open} onOpenChange={setOpen}>
      <Select.Trigger>Trigger</Select.Trigger>
      <AnimatePresence>
        {open && (
          <Select.Positioner keepMounted>
            <Select.Popup
              render={
                <motion.div
                  initial={{ opacity: 0 }}
                  animate={{ opacity: 1 }}
                  exit={{ opacity: 0 }}
                />
              }
            >
              <Select.Option>Option 1</Select.Option>
              <Select.Option>Option 2</Select.Option>
            </Select.Popup>
          </Select.Positioner>
        )}
      </AnimatePresence>
    </Select.Root>
  );
}

Animation states

Four states are available as data attributes to animate the popup, which enables full control depending on whether the popup is being animated with CSS transitions or animations, JavaScript, or is using the keepMounted prop.

Overriding default components

Use the render prop to override the rendered elements with your own components.

// Element shorthand
<Select.Popup render={<MySelectPopup />} />
// Function
<Select.Popup render={(props) => <MySelectPopup {...props} />} />

API Reference

SelectRoot

PropTypeDefaultDescription
alignOptionToTriggerbooltrueDetermines if the selected option inside the popup should align to the trigger element.
animatedbooltrueIf true, the Select supports CSS-based animations and transitions. It is kept in the DOM until the animation completes.
defaultOpenboolfalseIf true, the Select is initially open.
defaultValueanynullThe default value of the select.
disabledboolfalseIf true, the Select is disabled.
namestringThe name of the Select in the owning form.
onOpenChangefuncCallback fired when the component requests to be opened or closed.
onValueChangefuncCallback fired when the value of the select changes. Use when controlled.
openboolAllows to control whether the dropdown is open. This is a controlled counterpart of defaultOpen.
readOnlyboolfalseIf true, the Select is read-only.
requiredboolfalseIf true, the Select is required.
valueanyThe value of the select.

SelectTrigger

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
disabledboolfalseIf true, the component is disabled.
focusableWhenDisabledboolfalseIf true, allows a disabled button to receive focus.
labelstringLabel of the button
renderunionA function to customize rendering of the component.

SelectValue

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
placeholderstringThe placeholder value to display when the value is empty (such as during SSR).
renderunionA function to customize rendering of the component.

SelectIcon

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
renderunionA function to customize rendering of the component.

SelectBackdrop

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
containerunionfalseThe container element to which the Backdrop is appended to.
keepMountedboolfalseIf true, the Backdrop remains mounted when the Select popup is closed.
renderunionA function to customize rendering of the component.

SelectPositioner

PropTypeDefaultDescription
alignmentenum'start'The alignment of the Select element to the anchor element along its cross axis.
alignmentOffsetnumber0The offset of the Select element along its alignment axis.
anchorunionThe anchor element to which the Select popup will be placed at.
arrowPaddingnumber5Determines the padding between the arrow and the Select popup's edges. Useful when the popover popup has rounded corners via border-radius.
classNameunionClass names applied to the element or a function that returns them based on the component's state.
collisionBoundaryunion'clipping-ancestors'The boundary that the Select element should be constrained to.
collisionPaddingunion5The padding of the collision boundary.
containerunionThe container element to which the Select popup will be appended to.
hideWhenDetachedboolfalseIf true, the Select will be hidden if it is detached from its anchor element due to differing clipping contexts.
positionMethodenum'absolute'The CSS position method for positioning the Select popup element.
renderunionA function to customize rendering of the component.
sideenum'bottom'The side of the anchor element that the Select element should align to.
sideOffsetnumber0The gap between the anchor element and the Select element.
stickyboolfalseIf true, allow the Select to remain in stuck view while the anchor element is scrolled out of view.
trackAnchorbooltrueWhether the select popup continuously tracks its anchor after the initial positioning upon mount.

SelectPopup

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
idstringThe id of the popup element.
renderunionA function to customize rendering of the component.

SelectOption

PropTypeDefaultDescription
disabledboolfalseIf true, the select option will be disabled.
labelstringA text representation of the select option's content. Used for keyboard text navigation matching.
valueanynullThe value of the select option.

SelectOptionText

PropTypeDefaultDescription

SelectOptionIndicator

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
keepMountedboolfalseIf true, the item indicator remains mounted when the item is not selected.
renderunionA function to customize rendering of the component.

SelectGroup

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
renderunionA function to customize rendering of the component.

SelectGroupLabel

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
renderunionA function to customize rendering of the component.

SelectScrollUpArrow

PropTypeDefaultDescription
keepMountedboolfalseWhether the component should be kept mounted when it is not rendered.

SelectScrollDownArrow

PropTypeDefaultDescription
keepMountedboolfalseWhether the component should be kept mounted when it is not rendered.

SelectArrow

PropTypeDefaultDescription
classNameunionClass names applied to the element or a function that returns them based on the component's state.
hideWhenUncenteredboolfalseIf true, the arrow is hidden when it can't point to the center of the anchor element.
renderunionA function to customize rendering of the component.

Contents