Data input

Components that collect input from the user: text inputs, checkboxes, radios, fieldsets, search inputs, file dropzones. Labels above inputs (visible, never placeholder-as-label). Lazy-on-first-blur validation. Error messages persist on the page until resolved.

Text input

Label above. Helper text below. Errors are persistent until resolved — they don't flicker on every keystroke. Use aria-invalid + an error message with role="alert".

.form-field label above, never placeholder-as-label
We send password-reset emails here.
required + helper text
Cataloged ID must follow the format XXXX-YYYY-NNNN.
.error + aria-invalid + role="alert"

Checkbox

Native HTML <input type="checkbox"> with accent-primary. Tab order matches visual order. Pair every checkbox with a <label>.

<input type='checkbox' class='accent-primary' />

Radio

Native HTML <input type="radio"> with accent-primary. Group by shared name. Always inside a <fieldset> with a <legend> — see Fieldset below.

Visibility
<input type='radio' class='accent-primary' />

Fieldset / Legend

Used for groups of related controls (filter sidebar facet, radio group, checkbox group). Always include a <legend> — it's the group's accessible name.

Region
<fieldset> + <legend> native semantics — filter sidebar facet

SearchInput

Two variants of one search affordance. variant="landing" is the centred-and-capped invitation on the landing page, with optional hint chips beneath. variant="discover" is the flush, pre-fillable working affordance at the top of the discover results.

<SearchInput variant="landing" /> landing page hero
<SearchInput variant="discover" /> discover results — flush, pre-filled

Dropzone

Generic file-drop area — typographic empty-state framed by a dashed hairline border that intensifies on hover. Not a chunky tinted box. The Imports tab on a collection page uses this pattern to receive new imports.

Drop a CSV here to import

One row per specimen. Compound specimens share a catalog number across rows.

<Dropzone /> generic — single file