GitHub

Field Error

A presentational error line that sits under any input. Pass a resolved message string — it renders a danger-colored line (matching esa-form-field's error styling) or nothing when empty.

Stable .astro import EsaFieldError from '@esa/ecology/esa-field-error.astro';

Preview

Error: This field is required.

<EsaFieldError message="This field is required." />

Empty state

With no message the component renders nothing and collapses out of layout, so it never reserves a gap under the input.

(nothing rendered above)
<EsaFieldError message="" />
<EsaFieldError message={null} />

With icon

Set icon for a small leading alert glyph.

Error: Enter a valid email address.

<EsaFieldError message="Enter a valid email address." icon />

Under an input

It is presentational and composable — drop it beneath any control. Your validation layer decides the message.

Error: Enter a valid email address.

<label for="email">Email</label>
<input id="email" type="email" value="not-an-email"
       aria-invalid="true" aria-describedby="email-error" />
<EsaFieldError id="email-error" message="Enter a valid email address." icon />

API

PropTypeDefaultDescription
message string | null '' Resolved error message. Renders nothing when null or empty.
icon boolean true Show the leading alert icon. On by default — without it, an error line and a help line are the same element in the same slot differing only by colour, which is SC 1.4.1.
id string — The element id, so a control's aria-describedby can point at this message. Without one the association this component exists for cannot be written.

Accessibility

  • This does not announce itself. It is an .astro component rendered at build time, and it renders nothing at all when message is empty — so there is no element in the DOM for a live region to update. A live region has to already exist, and be empty, before the text arrives; one created together with its content is routinely not announced. This page previously claimed otherwise.
  • Its scope is therefore server-rendered errors already present on page load — the message a form comes back with after a failed round trip. For an error that appears during a session, use the control's own error-text: those keep a persistent empty message node exactly so the region can fire, and expose live-error to opt into announcing it.
  • Purely presentational — it does not own the input's aria-invalid or aria-describedby. Give it an id and point the control at it, as the example above does.
  • The leading icon is decorative (aria-hidden) and the text carries the meaning — but the icon is doing real work for sighted users, since colour alone cannot distinguish an error line from a hint (SC 1.4.1). Prefer icon on.

Theming surface

Every public token this component reads, extracted from its source at build time, split by blast radius: the hooks that belong to this component, then the shared and system tokens it consumes alongside everything else. 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.

Type roles it names

This component does not set a size, weight, face or tracking of its own — it names a composite, and the composite carries all five. A composite is a class rather than a token, so none of it appears in the tables below; re-theme text by re-pointing the token family, not by editing the component.

RoleRe-pointReach
.typography-body-xs
  • --typography-body-xs-font-family 'DM Sans', sans-serif via --typography-font-family-sans → --font-family-dm-sans
  • --typography-body-xs-font-size clamp(0.625rem, 0.56rem + 0.32vw, 0.75rem) via --font-size-100
  • --typography-body-xs-font-weight 350 via --typography-font-weight-regular → --font-weight-350
  • --typography-body-xs-letter-spacing 0.01em via --letter-spacing-default
  • --typography-body-xs-line-height 1.6 via --line-height-normal
+14 more components esa-breadcrumbs, esa-checkbox, esa-checkbox-group, esa-combobox, esa-command-palette, esa-empty-state, esa-entity-search, esa-header-nav, esa-input-tag, esa-progress-bar, esa-radio-group, esa-search-panel, esa-select, esa-textarea

Wired to this component

None. This component has no hooks of its own — it themes entirely through the shared tokens below, so every override here also moves its siblings.

Shared tokens it reads

Owned by a family or by the semantic layer. Still overridable — but scope the override (esa-foo { --form-border-color: … }) unless you mean to move everything that reads it. Reach says what else that is.

Token Reach Resolves to
--form-help-gap component forms group · +5 more 0.25rem via --spacing-100
--color-content-utility-danger semantic every component #ce2c31 via --color-red-11
--spacing-100 primitive every component 0.25rem