GitHub

Form Field

A presentational layout wrapper — label row, control slot, and hint/error text. Pure .astro with no runtime JS; drop any control into the slot. Error text replaces help text when present.

Stable .astro import EsaFormField from '@esa/ecology/esa-form-field.astro';

Preview

We will never share your email.

<FormField label="Email" helpText="We will never share your email.">
  <input type="email" placeholder="you@example.com" />
</FormField>

States

Mark a field required, surface an errorText in place of help text, or disabled the whole field.

Permit ID is required.

This field cannot be edited.

<FormField label="Project name" required>
  <input type="text" />
</FormField>

<FormField label="Permit ID" errorText="Permit ID is required." required>
  <input type="text" aria-invalid="true" />
</FormField>

<FormField label="Locked field" helpText="This field cannot be edited." disabled>
  <input type="text" disabled value="Read only" />
</FormField>

Sizes

The size prop scales the label; size the control yourself to match.

<FormField label="Extra small label" size="xs"></FormField>
<FormField label="Small label" size="sm"></FormField>
<FormField label="Medium label" size="md"></FormField>
<FormField label="Large label" size="lg"></FormField>

API

PropTypeDefaultDescription
label string '' Label rendered above the control slot.
helpText string '' Helper text shown below the control.
errorText string '' Error message; replaces help text when present.
required boolean false Renders an asterisk on the label.
disabled boolean false Dims the field and blocks pointer events.
size 'xs' | 'sm' | 'md' | 'lg' 'md' Scales the label font size.

The control goes in the default slot — the wrapper makes no assumptions about it.

Accessibility

  • The wrapper is presentational only; associate the label and control yourself (e.g. a for/id pair) since the slot content is opaque to it.
  • The required asterisk carries an aria-label="required".
  • Set aria-invalid="true" on the slotted control whenever errorText is shown.
  • disabled dims the field and blocks pointer events; also disable the underlying control for keyboard users.

Theming surface

Every public token this component reads, extracted from its source at build time. The Resolves to column walks each token's real lineage — component → semantic → primitive → raw value — so you can see exactly where re-pointing it lands. A spoke re-skins by overriding these in its theme-<slug>.css; component internals are never edited. No hook for what you need? File it with /request-lego.

TokenTierResolves to
--form-error-color component #ce2c31 via --color-danger-strong--color-red-11
--form-font-size-lg component clamp(0.875rem, 0.77rem + 0.52vw, 1.125rem) via --type-size-300
--form-font-size-md component clamp(0.75rem, 0.66rem + 0.44vw, 0.9375rem) via --type-size-200
--form-font-size-sm component clamp(0.625rem, 0.56rem + 0.32vw, 0.75rem) via --type-size-100
--form-font-size-xs component clamp(0.5rem, 0.44rem + 0.3vw, 0.625rem) via --type-size-050
--form-help-color component #838383 via --color-text-muted--color-gray-10
--form-help-gap component 0.25rem via --spacing-100
--form-label-color component #646464 via --color-text-secondary--color-gray-11
--form-label-gap component 0.25rem via --spacing-100
--color-danger-strong semantic #ce2c31 via --color-red-11
--type-size-100 semantic clamp(0.625rem, 0.56rem + 0.32vw, 0.75rem)
--font-weight-medium primitive 500