Skip to main content
VelinStyle v1.1.0
⌂ Home
  1. Docs
  2. Components
  3. Form summary

Form summary

The <velin-form-summary> Web Component turns native constraint validation into an accessible error summary: one focusable panel listing every invalid field, with aria-invalid and aria-describedby wired up per field.

Why not native validation?

The browser's own validation bubble shows one error at a time, disappears on its own, cannot be styled, and is inconsistently exposed to assistive technology. On a form with several problems the user has to discover them one submit at a time.

This component sets novalidate on the form and takes over: on submit it collects every invalid field, renders a persistent summary, and moves focus there. Constraint validation itself is unchanged — required, type, pattern, min, maxlength and custom messages all still apply.

Basic

Place the element inside the form, or anywhere on the page with for pointing at the form id.

<form id="signup">
  <velin-form-summary heading="There is a problem with your details"></velin-form-summary>

  <label class="velin-form-label" for="email">Email address</label>
  <input class="velin-form-control" id="email" name="email" type="email" required>

  <button type="submit" class="velin-btn velin-btn--primary">Create account</button>
</form>

Submitting with errors renders a role="alert" panel, focuses it, and announces the number of fields needing attention. Each summary entry links to its field; activating one moves focus straight to the input. Errors clear per field as soon as that field becomes valid, so the summary shrinks as the user works through it — it never re-flags a field the user has not submitted yet.

Custom messages and containers

By default the browser's validationMessage is used, which is already localised. Override it per field, and control how the field is named in the summary:

<input id="name" name="name" required
       data-error-message="Enter your full name"
       data-error-label="Name">

Messages are injected as a .velin-field-error element after the field and referenced from aria-describedby. To control placement, supply your own container — the component fills it instead of creating one, and leaves it in the DOM when the error clears:

<input id="email" name="email" type="email" required>
<p class="velin-field-error" data-velin-error-for="email"></p>

Existing aria-describedby hints are preserved: the error id is appended, so a field can point at both its hint and its error.

Attributes

AttributeDefaultNotes
forForm id; omit when nested inside the form
headingThere is a problemSummary heading text
native-validationKeeps the browser's own bubbles (does not set novalidate)

Per-field attributes: data-error-message, data-error-label, data-error-ignore (skip the field entirely), and data-velin-error-for on a message container. Disabled fields are always skipped, and a radio group is listed once rather than per radio.

JavaScript API

const summary = document.querySelector('velin-form-summary');

summary.validate();          // returns true when the form is valid
summary.focusFirstError();   // move focus to the first invalid field
summary.clear();             // drop the summary and all field error state

summary.errors;              // [{ field, label, message }]
summary.form;                // the bound form element

Events

Accessibility

Contract status in core/a11y/component-contracts.json: pass. Pair it with the CSS-only states on Validation and <velin-persist> for Redundant Entry.