Form Field

The wrapper that gives a control its label, its hint and its error line, so every field in every form reads the same way.

import from ~/components/ui/form-field

Anatomy

Lowercase, no spaces. This becomes the repository name.

label + control + description

Three parts in a fixed order. The control is the child, everything around it is a prop.

Required

required

Adds the asterisk to the label. It is a visual marker, so still set required on the control itself.

Error

Enter a valid email address.

Pick a region before you continue.

error

The error replaces the description rather than stacking under it, so the field never grows two lines of hint. Set aria-invalid on the control at the same time.

Naming a GROUP of controls

Endeavor *

Which discipline this project leads with.

as="group"

A radio group, a checkbox group, a segmented control: anything where several controls share one name. The legend names the set; each radio still has its own label.

In context

Lowercase, no spaces.

Optional. Visible to everyone on the team.

Enter a valid email address.

a whole form

One FormField per control keeps the label voice, the hint size and the error line identical down the form.

Rules

Do

Wire htmlFor to the id of the control it wraps. An unassociated label is not a label.
Use as="group" for a SET of controls that share one name. It renders a fieldset and a legend.
Set aria-invalid on the control whenever you pass error, so assistive tech hears what the border says.
Write errors that say how to fix it: "Enter a valid email address", not "Invalid".
Use it for every labelled control in a form, including the ones you think are obvious.

Don't

Never point htmlFor at a radiogroup container. It is not a labelable element, so the name silently attaches to nothing.
Do not pass both a description and an error expecting both to show. Error wins by design.
Do not hand-roll a label or an error line next to a control. That is the drift this prevents.
Do not rely on color alone to signal the error. The message line carries the meaning.
Do not hide the label and lean on the placeholder. Sighted users lose it the moment they type.