All components
Forms
Select
stable
Since 1.2
Single-choice picker with sections, rich items, a searchable combo-box mode, and a popover-on-web / sheet-on-native overlay.
Forms
primitive
Form Control
Needs State Matrix
import { Select } from '@ivim/native/components';
When to use
Use when
Exactly one value is chosen from a list too long to show all at once.
Options need more than a label — a description, an icon, a section heading.
The list is long enough to need filtering, via isSearchable.
Don't use when
There are only a few short options and they should all stay visible — use RadioGroup or ButtonGroup.
More than one value may be chosen — use MultiSelect.
The value is free text — use Input.
Playground
Adjust the controls to preview live prop combinations. The code snippet updates to match the current selection.
Plan
size
size
sm
md
lg
Searchable
isSearchable
Required
isRequired
Disabled
isDisabled
Full width
fullWidth
<Select />
Example
Preview
Code
States
Default
Plan
Preselected
Plan
Searchable (combo-box)
Plan
With sections
Assignee
One option disabled
Plan
Required, with description
Plan
*
You can change this later.
With an error
Plan
Choose a plan to continue
With a tooltip
Plan
Disabled
Plan
Full width
Plan
Anatomy
The parts that compose this component.
1
Label
Field name; folded into the trigger’s accessible name.
2
Trigger
Shows the current value or the placeholder, and reports expanded state.
3
Overlay
Popover on web, bottom sheet on native.
4
Search field
Optional filter inside the overlay — the combo-box form.
5
Option
Label, optional description and leading slot, with a check when selected.
6
Section heading
Groups adjacent options sharing a section.
Guidelines
Do
Always pass label, so the trigger announces what the value is for rather than just the value.
Do
Turn on isSearchable once the list passes roughly ten options.
Do
Group related options with section rather than relying on order alone.
Don't
Use a select for two mutually exclusive options — a toggle or a button group is one interaction shorter.
Props
Public props for this component. Required props are marked; defaults reflect the component implementation.
options
required
SelectOption[]
{ value, label, description?, leading?, isDisabled?, section? }.
selectedKey / defaultSelectedKey
string | null
Controlled and uncontrolled selection.
onSelectionChange
(key: string) => void
Fires with the newly selected key.
isSearchable
boolean
default: false
Adds a filter field inside the overlay — the combo-box form.
emptyState
ReactNode
Shown when a search matches nothing.
label / description / errorMessage
ReactNode
Field anatomy; all reach the trigger’s accessible name.
tooltip
string
Contextual help behind a small info affordance beside the label. Supplementary only — anything required to act belongs in description.
isDisabled / isInvalid / isRequired
boolean
default: false
Field state.
size
'sm' | 'md' | 'lg'
default: 'md'
Trigger height, padding, and text scale.
aria-label
string
Accessible name when there is no visible label, or when the label is not plain text.
placeholder / fullWidth
string / boolean
default: 'Select' / false
Trigger text when nothing is selected, and whether the trigger fills its container.
Deviations from Untitled UI
Where this component deliberately differs from Untitled UI's API, and why. These are kept choices, not gaps to close.
Untitled UI
`hint?: ReactNode` doubling as error text when invalid
Ours
`description` + `errorMessage`
UUI's `hint` is a UUI-ism layered over React Aria, which itself uses `description`/`errorMessage`. We follow the substrate; both slots can render simultaneously.
Untitled UI
Compound children (`Select.Item`, `Dropdown.Root/Popover/Menu`, `Tabs.List/Panel`)
Ours
data-driven `items` / `options` / `columns` arrays
RN has no DOM portals and compound context patterns complicate static typing and testing. Typed arrays are serializable, exhaustively checkable, and match RN list idioms. See grammar rule G8.
Accessibility
Roles and screen-reader behavior this component provides, plus keyboard interactions.
•
The trigger announces label, requirement, current value, and any error as one name, and reports expanded state.
•
Options announce their selected state; the previous implementation had no listbox or option roles at all, so assistive tech could not tell this was a choice.
•
Arrow keys move the active option on web, Enter selects, and Escape dismisses.
•
A disabled option can never become selected.
•
The overlay list is not itself an accessibility element, so each option stays individually reachable on iOS.
Tab
Moves focus to the trigger.
Space / Enter
Opens the overlay, or selects the active option.
Arrow Up / Down
Moves the active option, skipping disabled ones.
Home / End
First or last enabled option.
Escape
Dismisses the overlay.
Platform & RTL
Behavior that differs across the platforms this component runs on.
Web
An inline popover anchored under the trigger, with full keyboard navigation.
iOS
A bottom sheet — a small floating list is awkward to hit and easy to dismiss by accident on a touch screen.
Android
A bottom sheet, matching iOS.
RTL
Trigger content, chevron, and option rows mirror with the writing direction.
State coverage
Interaction and visual states this component supports.
default
focus
error
disabled
selected
Token references
Semantic design tokens this component page exercises. Tap one to edit it live.
Related components
Components that solve adjacent problems or compose with this one.
MultiSelect
Multiple-choice picker with search, select-all, removable value tags, a custom footer, and distinct empty and no-match states.
RadioGroup
One-of-many choice as a list or as selectable cards, with icon, avatar, price, badge, and secondary-action slots.
Menu
Action menu owning its trigger and overlay, with sections, icons, shortcuts, destructive items, and a Popover for interactive content.
Input
Single-line text entry, with TextField for labelled fields and InputGroup for adornments, prefixes, and attached controls.