A dropdown for picking one option, wrapping the Base UI Select. Full keyboard navigation and typeahead come from the foundation; the popup opens with a small fade and settle.

Playground

Every control maps to a prop. The Code tab always shows the markup for exactly what you've configured.

Variants

Bordered is the default; borderless trades the border for a muted fill, the same surface as a secondary button.

States

Open, highlighted, and selected are live; try the examples. Disabled and invalid are the ones you set, and invalid turns the border and hint to the danger color.

Pick a plan to continue.

Styling states

The highlighted item carries data-highlighted, the chosen one data-selected, and the trigger data-popup-open while open, so custom styling never needs JavaScript:

.ub-select-item[data-highlighted] {
  background: var(--ub-bg-muted);
}

Props

Each part passes the full Base UI API through. The essentials:

PropTypeDefaultDescription
SelectRoot.defaultValuestringThe option selected on first render, when uncontrolled.
SelectRoot.valuestringControlled selection. Pair with onValueChange.
SelectRoot.onValueChange(value) => voidCalled when the selection changes.
SelectTrigger.placeholderReactNodeShown while nothing is selected.
SelectTrigger.variant"default" | "borderless""default"Bordered, or a muted fill with no border.
SelectRoot.itemsRecord<value, label>Value to label map; required for the trigger to show the selected label before the dropdown has opened.
SelectRoot.size"default" | "compact""default"Sizes the trigger and dropdown items together: 36px tall with 16px text by default, 28px with 14px text compact.
SelectTrigger.disabledbooleanfalseBlocks opening the select.
SelectTrigger.invalidbooleanfalseDanger border, ring, and hint, plus aria-invalid; a surrounding Field sets it automatically.
SelectTrigger.leadingIconReactNodeIcon before the value. Decorative.
SelectTrigger.hintReactNodeHelper text below the trigger, linked via aria-describedby.
SelectItem.valuestringIdentity of the option.
SelectItem.disabledbooleanfalseBlocks choosing this option.
SelectContent.sidePositionerSideWhich side of the trigger the popup opens on; below by default. Also align.
SelectContent.sideOffsetnumber4Gap between the trigger and the popup, in pixels.

Agent instructions

Working with a coding agent? Paste this into its context, or point it at llms.txt for the whole library.

SelectRoot, SelectTrigger, SelectContent, SelectItem, from @usebones/react.
- SelectRoot: defaultValue or value + onValueChange (the callback value can be null); size sizes the trigger and dropdown items together. Always pass items (a value to label record) so the trigger shows the selected label instead of the raw value.
- SelectTrigger: placeholder, variant "default" | "borderless", invalid, leadingIcon, hint. The chevron renders automatically; there is no trailing icon slot.
- SelectContent handles the portal and positioning. SelectItem children are the label; the selected check renders automatically.
- Inside FieldRoot, drop invalid and hint and use FieldLabel, FieldDescription, and FieldError instead.
- Restyle in CSS via .ub-select-trigger, .ub-select-popup, .ub-select-item, [data-highlighted], [data-selected], [data-popup-open]. Tokens only.