Select from @prepared911/ui/select is a Radix Select listbox with label, keyboard navigation, and grouped-item support wired in. The component handles combobox semantics, roving focus inside the dropdown, and label association; your job is to provide the visible label, required-field indicators, and validation feedback.
What the component handles
Role assignment. Trigger → combobox; menu → listbox; items → option. aria-expanded, aria-selected, aria-disabled are managed.
Label association. Visible labels pair via htmlFor + id. When hideLabel is set, the label becomes aria-label so screen readers still get it.
Keyboard navigation. Tab, Enter/Space, arrow keys, Home/End, Escape behave per the listbox pattern.
Group semantics. Grouped items expose group names to screen readers during navigation.
What you must provide
Label. Always pass label. "Visually hidden" is fine (hideLabel) when space is truly constrained.
Required indicator. Set required; pair with a visible asterisk or an inline "required" string so sighted users see it too.
Invalid state. On validation failure, set aria-invalid and associate an error message via aria-errormessage.
Placeholder vs. value. Don't rely on placeholder as a label; it disappears on selection.
Keyboard behavior
Tab / Shift+Tab moves focus to / from the trigger.
Enter / Space opens the dropdown.
Arrow Up / Down navigates options; Home / End jump to first / last.
Enter / Space on an option selects and closes the menu.
Escape closes without selecting.
Semantics and roles
Trigger exposes role="combobox" with aria-expanded.
Menu is role="listbox"; items are role="option" with aria-selected on the current value.
Disabled options expose aria-disabled and are skipped by keyboard navigation.
Enter → menu opens → "Apple, option, 1 of 3, selected".
Arrow down → "Banana, option, 2 of 3".
Enter → menu closes → "Choose fruit, combobox, Banana, collapsed".
Grouped items announce the group ("Fruits, group, Apple, option, 1 of 2").
Focus management
Focus moves to the first option (or the selected option) when the menu opens and returns to the trigger when it closes. Don't override this unless the implementation truly requires it.
Required fields and validation
Known caveats
Long options. Very long labels can push the menu wider than the trigger. Test at narrow widths and in localized strings.
Many items. At roughly 20+ items, a Combobox with search scans better than a Select.
Native select fallback. This component does not render a native <select>; don't expect native mobile pickers.