Form section
A titled group of esa-form-field-wrapped controls that ends in an action row — the unit intake forms, settings panels, and dialog bodies are assembled from.
Default
A project-details section from an environmental review intake. Each control sits in an
esa-form-field wrapper, which owns the label, required asterisk, and help text —
the controls themselves render chrome-free. Short, related fields (lead agency / county) pair
on one row; everything else runs single column. The action row closes the section: primary
submit first, ghost cancel beside it.
Project details
Tell us about the project under review. Fields marked * are required.
As it appears on the notice of preparation.
Summarize the location, scope, and anticipated construction activity.
Validation state
The same section after a failed submit: the name is missing and no pathway is selected.
Errors attach at the lowest level that can render them. Self-chromed controls
(esa-text-field, esa-select, esa-textarea) take
error-text — one attribute turns the border red, sets aria-invalid,
and renders the message in place of help text. Option groups have no error prop, so an
esa-field-error line goes directly after the control, inside the same wrapper.
Project details
Tell us about the project under review. Fields marked * are required.
Summarize the location, scope, and anticipated construction activity.
Select a review pathway.
Composition notes
-
Every control gets an
esa-form-fieldwrapper, and the wrapper owns the field chrome — label, required asterisk, help text. Leave the control's ownlabel/help-textattributes unset so the field isn't labeled twice. -
Error messages live in components, never ad-hoc styled spans:
error-texton controls with built-in chrome, anesa-field-errordirectly after controls without one (radio and checkbox groups). The error replaces the field's help text — don't stack both. - The action row belongs to the section, not to any field: primary action first, ghost cancel second, left-aligned on the same axis as the labels, separated from the fields by a divider.
-
Single column by default. Only pair short, related fields on one row, and collapse the pair
on narrow viewports. Controls run full width — the section's
max-widthsets the measure, not the individual control. -
One size across the section: everything defaults to
mdon the shared scale, so inputs, selects, and buttons share heights and line up when they meet on a row.