Skip to content
View as Markdown

Inputs

Select

A native select with a fluid chevron, accessible and zero-JS. Compose it inside a Field for its label, description and error.

Import

TSX
import { Field, Select } from "@loamui/core";

Usage

Every example has a CSS tab. That’s the real, complete stylesheet for the component: plain, static CSS, with nothing running in the browser.

Basic usage

Inside Field.Root the select reads its id from the field, so Field.Label is wired without any props.

Starting unanswered

An unanswered start is an option like any other: a first child with an empty value, disabled so it can never be chosen. The select starts on it, so a required field the user skipped is caught, and the prompt reads muted until answered.

Groups and disabled options

Options pass straight to the native select, so optgroup and disabled work exactly as the platform defines them.

With a description

Field.Description links to the select via aria-describedby, the same wiring every control gets inside a Field.

Where you are resident for tax.

Error state

A Field.Error before the control marks the field invalid and is announced: the message's presence is the state.

Guidance

When to use it

  • For choosing one option from a longer list (roughly 5+) where showing them all would take too much space.
  • When the options are familiar and the user doesn't need to compare them side by side.

When not to

  • For a small set of options the user should see at once: use Radio, which shows every choice up front.
  • For yes/no or on/off: use Checkbox or Switch.
  • For unrestricted text entry: use Input.

Accessibility

  • Wraps a native <select>, so keyboard interaction, typeahead and the mobile picker come from the platform.
  • Inside a Field.Root it self-wires: the label, description and error are linked via id / aria-describedby / aria-invalid, with the error announced as role="alert". See the Field page.
  • A prompt is a disabled first option with an empty value, so it is never a selectable value; the select starts on it when nothing else is chosen.
  • Under forced colours the danger border colour is dropped, so an invalid select carries its state as an outline in a system colour, with the focus ring offset further out.

How it works

Start without a value

Make the first child a disabled option with an empty value, so the field starts unanswered and required validation catches an untouched select. With no such option the first real one is pre-selected, and users who skip the field silently submit an answer they never chose. Write the prompt as a native option element.

Order the options

List options alphabetically so users can predict where an answer sits in a long menu, the reason to use a Select at all. Depart only for an order that is genuinely more useful in the domain, like months in calendar order or years newest-first.

A select conceals its options

Until opened, the menu shows one value and hides every alternative, so users can't survey or compare the choices. The cost shows up in usability testing: people try to type into the closed control, mistake the focused option for a selected one, and struggle to operate the menu zoomed in. That is the cost that makes RadioGroup the better control for small sets. Reserve Select for long lists of familiar answers users recognise rather than weigh up.

Error messages

Say what happened and how to fix it, in the words of the question itself. See the writing guidance on the Field page.

SituationMessage
Nothing is selectedSelect [whatever the label asks for]

Props

PropTypeDefaultDescription
childrenReactNode—Native <option> / <optgroup> elements, passed straight through. A leading <option value="" disabled> is the unanswered start.
wrapperPropsPartProps<"div">—Props for the box around the select, which positions the chevron. className, style, ref and every other prop land on the <select> itself; this is the one way to reach the box.
...othersSelectHTMLAttributes—All native <select> props, and ref, are forwarded to the <select>, except size (a listbox is not this component).