A dropdown for choosing from a list of options.
import { Select } from '@oztix/roadie-components/select'
Pass string children to Select.Item for automatic ItemText + ItemIndicator
wrapping. Use Select.Content as a convenience wrapper for Portal + Positioner + Popup.
normal is the default: a plain fill with a visible border, like a normal Button. subtle sits on a tinted fill. subtler has no fill or border at rest, for quiet controls inside something else, such as rows per page under a table.
normal and subtle triggers use is-interactive-field for state-based
colour transitions: neutral at rest, accent on focus/open, danger when invalid.
A subtler trigger uses is-interactive instead, so it behaves like a subtler
Button: no fill at rest, a light fill on hover, press and while open, and a
danger edge when invalid.
Wrap Select in Field for consistent layout, labels, and error handling. Field provides spacing, label wiring, and context flow automatically.
Select also has its own Select.Label for standalone usage without a Field
wrapper. Use showIndicator to show a required or optional indicator.
Set multiple to let people pick more than one option. The popup stays open
between picks. The trigger lists the labels that fit and counts the rest, such
as "Bee Gees, Custard +2", while screen readers hear every label. value,
defaultValue and onValueChange then take an array.
Use Select when the list of options is known, short, and fixed. The user picks from a closed set. They don't need to search or type a custom value.
<Select.Trigger emphasis='subtler' size='sm' />
Do
Use subtler for a control that adjusts what is already on screen, such as rows per page, sort order or a chart's comparison, beside other subtler buttons. A subtler trigger takes only the width of its value and icon, where normal and subtle fill their container. If the value changes length, hold the width with the widest label so the controls beside it stay put.
Don’t
Don't use subtler for a select in a form. With no border at rest, it doesn't read as a field to fill in next to an Input.
If users are likely to search the list, the list is long (15+ items), or options load asynchronously, use Combobox.
| Question | Select | Combobox |
|---|---|---|
| Can the user type to filter? | No (typeahead only) | Yes |
| Is the list longer than ~15 items? | Avoid | Preferred |
| Are options loaded from an API? | No | Yes |
| Can the user enter a custom value? | No | Possible |
| Does the user know roughly what they want? | Maybe not. They browse. | Yes. They search. |
Select delegates all keyboard handling to Base UI:
Select.Label or an aria-label on the trigger.Select.ItemIndicator provides a visible check for the selected item. Include it for clarity.modal={true}). Set modal={false} if the select appears in a non-blocking context like a toolbar.A ref to access the hidden input element.
Identifies the field when a form is submitted.
Identifies the form that owns the hidden input. Useful when the select is rendered outside the form.
Provides a hint to the browser for autofill. @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/autocomplete
The id of the Select.
Whether the user must choose a value before submitting a form.
Defaults to false.
Whether the user should be unable to choose a different option from the select popup.
Defaults to false.
Whether the component should ignore user interaction.
Defaults to false.
Whether multiple items can be selected.
Defaults to false.
Whether moving the pointer over items should highlight them. Disabling this prop allows CSS `:hover` to be differentiated from the `:focus` (`data-highlighted`) state.
Defaults to true.
Whether the select popup is initially open. To render a controlled select popup, use the `open` prop instead.
Defaults to false.
Event handler called when the select popup is opened or closed.
Event handler called after any animations complete when the select popup is opened or closed.
Whether the select popup is currently open.
Determines if the select enters a modal state when open. - `true`: user interaction is limited to the select: document page scroll is locked and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior.
Defaults to true.
A ref to imperative actions. - `unmount`: Ends the closing phase of the select after an externally controlled closing animation finishes. Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the select completes closing on its own. Whether it leaves the DOM is decided by `keepMounted` on the portal. - `close`: Closes the select imperatively when called.
Data structure of the items rendered in the select popup. When specified, `<Select.Value>` renders the label of the selected item instead of the raw value. @example ```tsx const items = { sans: 'Sans-serif', serif: 'Serif', mono: 'Monospace', cursive: 'Cursive', }; <Select.Root items={items} /> ```
When the item values are objects (`<Select.Item value={object}>`), this function converts the object value to a string representation for display in the trigger. If the shape of the object is `{ value, label }`, the label will be used automatically without needing to specify this prop.
When the item values are objects (`<Select.Item value={object}>`), this function converts the object value to a string representation for form submission. If the shape of the object is `{ value, label }`, the value will be used automatically without needing to specify this prop.
Custom comparison logic used to determine if a select item value matches the current selected value. Useful when item values are objects without matching referentially. Defaults to `Object.is` comparison.
The uncontrolled value of the select when it's initially rendered. To render a controlled select, use the `value` prop instead.
The value of the select. Use when controlled.
Event handler called when the value of the select changes.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectPopupProps
Determines the element to focus when the select popup is closed. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (trigger or previously focused element). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing.
No additional props. It forwards all standard HTML attributes to the underlying element.
No additional props. It forwards all standard HTML attributes to the underlying element.
No additional props. It forwards all standard HTML attributes to the underlying element.
No additional props. It forwards all standard HTML attributes to the underlying element.
No additional props. It forwards all standard HTML attributes to the underlying element.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectItemProps
A unique value that identifies this select item.
Defaults to null.
Whether the component should ignore user interaction.
Defaults to false.
Specifies the text label to use when the item is matched during keyboard text navigation. Defaults to the item text content if not provided.
Inherited from NonNativeButtonProps
Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `true` if the rendered element is a native button.
Defaults to false.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectItemIndicatorProps
Whether to keep the HTML element in the DOM when the item is not selected.
No additional props. It forwards all standard HTML attributes to the underlying element.
CSS class applied to the element, or a function that returns a class based on the component's state.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectPopupProps
Determines the element to focus when the select popup is closed. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (trigger or previously focused element). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectPortalProps
A parent element to render the portal element into.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectPositionerProps
Whether the positioner overlaps the trigger so the selected item's text is aligned with the trigger's value text. This only applies to mouse input and is automatically disabled if there is not enough space.
Defaults to true.
Inherited from UseAnchorPositioningSharedParameters
An element to position the popup against. By default, the popup will be positioned against the trigger.
Determines which CSS `position` property to use.
Defaults to 'absolute'.
Which side of the anchor element to align the popup against. May automatically change to avoid collisions.
Defaults to 'bottom'.
Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner sideOffset={({ side, align, anchor, positioner }) => { return side === 'top' || side === 'bottom' ? anchor.height : anchor.width; }} /> ```
Defaults to 0.
How to align the popup relative to the specified side.
Defaults to 'center'.
Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner alignOffset={({ side, align, anchor, positioner }) => { return side === 'top' || side === 'bottom' ? anchor.width : anchor.height; }} /> ```
Defaults to 0.
An element or a rectangle that delimits the area that the popup is confined to.
Defaults to 'clipping-ancestors'.
Additional space to maintain from the edge of the collision boundary.
Defaults to 5.
Whether to maintain the popup in the viewport after the anchor element was scrolled out of view.
Defaults to false.
Minimum distance to maintain between the arrow and the edges of the popup. Use it to prevent the arrow element from hanging out of the rounded corners of a popup.
Defaults to 5.
Whether to disable the popup from tracking any layout shift of its positioning anchor.
Defaults to false.
Determines how to handle collisions when positioning the popup. `side` controls overflow on the preferred placement axis (`top`/`bottom` or `left`/`right`): - `'flip'`: keep the requested side when it fits; otherwise try the opposite side (`top` and `bottom`, or `left` and `right`). - `'shift'`: never change side; keep the requested side and move the popup within the clipping boundary so it stays visible. - `'none'`: do not correct side-axis overflow. `align` controls overflow on the alignment axis (`start`/`center`/`end`): - `'flip'`: keep side, but swap `start` and `end` when the requested alignment overflows. - `'shift'`: keep side and requested alignment, then nudge the popup along the alignment axis to fit. - `'none'`: do not correct alignment-axis overflow. `fallbackAxisSide` controls fallback behavior on the perpendicular axis when the preferred axis cannot fit: - `'start'`: allow perpendicular fallback and try the logical start side first (`top` before `bottom`, or `left` before `right` in LTR). - `'end'`: allow perpendicular fallback and try the logical end side first (`bottom` before `top`, or `right` before `left` in LTR). - `'none'`: do not fallback to the perpendicular axis. When `side` is `'shift'`, explicitly setting `align` only supports `'shift'` or `'none'`. If `align` is omitted, it defaults to `'flip'`. @example ```jsx <Positioner collisionAvoidance={{ side: 'shift', align: 'shift', fallbackAxisSide: 'none', }} /> ```
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectScrollDownArrowProps
Whether to keep the HTML element in the DOM while the select popup is not scrollable.
Defaults to false.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectScrollUpArrowProps
Whether to keep the HTML element in the DOM while the select popup is not scrollable.
Defaults to false.
CSS class applied to the element, or a function that returns a class based on the component's state.
`subtler` drops the fill and border for quiet in-context controls, such as rows per page.
Defaults to 'normal'.
Defaults to 'md'.
Deprecated: Form controls take their colour from state; `is-interactive-field` handles it. Will be removed in v3.0.0.
Inherited from SelectTriggerProps
Whether the component should ignore user interaction.
Inherited from NonNativeButtonProps
Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `true` if the rendered element is a native button.
Defaults to false.
CSS class applied to the element, or a function that returns a class based on the component's state.
Inherited from SelectValueProps
Accepts a function that returns a `ReactNode` to format the selected value. Treat the value as read-only: in `multiple` mode it may be a shared frozen array when nothing is selected. @example ```tsx <Select.Value> {(value: string | null) => value ? labels[value] : 'No value'} </Select.Value> ```
The placeholder value to display when no value is selected. This is overridden by `children` if specified, or by a null item's label in `items`.