Formsstable.error-summary
Error summary
A box at the top of a form that lists every error after a failed submit, each linked to its field.
Shown only after a submit fails (UX guide §6.2): all errors at once, in the order of the form. Each entry links to its field (#fieldId), so a click or Enter jumps there. The same messages also appear at the fields themselves.
After rendering, move focus to the summary (el.focus() — it has tabindex="-1") and scroll it into view below the sticky top bar. It has role="alert", so the count and the list are announced.
The title states the number of problems ("Bitte prüfe 2 Angaben"). Messages say what to do, not what is wrong in technical terms. Server errors (problem+json errors[]) map onto the same entries.
Examples
Two errors (default title)
Bitte prüfe 2 Angaben
Data
render({
"errors": [
{
"fieldId": "email",
"message": "E-Mail ist unvollständig"
},
{
"fieldId": "birthdate",
"message": "Geburtsdatum fehlt"
}
]
})Markup
<div class="error-summary" id="error-summary" tabindex="-1" role="alert" aria-labelledby="error-summary-title">
<h2 class="error-summary__title" id="error-summary-title">Bitte prüfe 2 Angaben</h2>
<ul><li><a href="#email">E-Mail ist unvollständig</a></li><li><a href="#birthdate">Geburtsdatum fehlt</a></li></ul>
</div>Custom title and id
Angaben zur erziehungsberechtigten Person fehlen
Data
render({
"id": "guardian-errors",
"title": "Angaben zur erziehungsberechtigten Person fehlen",
"errors": [
{
"fieldId": "guardian-name",
"message": "Gib den Namen der erziehungsberechtigten Person ein."
}
]
})Markup
<div class="error-summary" id="guardian-errors" tabindex="-1" role="alert" aria-labelledby="guardian-errors-title">
<h2 class="error-summary__title" id="guardian-errors-title">Angaben zur erziehungsberechtigten Person fehlen</h2>
<ul><li><a href="#guardian-name">Gib den Namen der erziehungsberechtigten Person ein.</a></li></ul>
</div>Data contract
What render(data) accepts — validated against this JSON Schema in development and tests. Unknown fields are rejected. The same schema is in components.json.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | optional | "error-summary" | Id of the box; the title gets {id}-title. Must be unique on the page.pattern ^[A-Za-z][\w-]*$ |
title | string | optional | — | Heading. Defaults to "Bitte prüfe 1 Angabe" / "Bitte prüfe {n} Angaben". min 1 chars |
errors | array of objects | required | — | One entry per invalid field, in form order. min 1 items |
errors[].fieldId | string | required | — | Id of the invalid control (link target #fieldId). For a choice group use the id of its first input ({id}-1).pattern ^[A-Za-z][\w-]*$ |
errors[].message | string | required | — | What to do, usually the same text as the field's error ("Gib ein Geburtsdatum ein."). min 1 chars |
JSON Schema
{
"type": "object",
"additionalProperties": false,
"required": [
"errors"
],
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z][\\w-]*$",
"default": "error-summary",
"description": "Id of the box; the title gets `{id}-title`. Must be unique on the page."
},
"title": {
"type": "string",
"minLength": 1,
"description": "Heading. Defaults to \"Bitte prüfe 1 Angabe\" / \"Bitte prüfe {n} Angaben\"."
},
"errors": {
"type": "array",
"minItems": 1,
"description": "One entry per invalid field, in form order.",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"fieldId",
"message"
],
"properties": {
"fieldId": {
"type": "string",
"pattern": "^[A-Za-z][\\w-]*$",
"description": "Id of the invalid control (link target `#fieldId`). For a choice group use the id of its first input (`{id}-1`)."
},
"message": {
"type": "string",
"minLength": 1,
"description": "What to do, usually the same text as the field's error (\"Gib ein Geburtsdatum ein.\")."
}
}
}
}
}
}Markup & states
Root: div.error-summary — usable without render() by writing the markup directly.
Attributes
| Attribute | Values | Default | Description |
|---|---|---|---|
role="alert" | — | — | Announced when inserted. |
tabindex="-1" | — | — | Can receive focus programmatically after submit. |
aria-labelledby | "{id}-title" | — | Named by its heading. |
Parts
| Part | Description |
|---|---|
.error-summary__title | The h2 title with the number of problems: semibold, --color-danger-text. |
ul > li > a[href="#fieldId"] | Linked error messages. |
Behaviour & events
Module: (page code)
Render on failed submit, then summary.focus() and scroll into view. Remove it when the form is submitted again successfully. Clicking a link moves focus to the field (native fragment navigation focuses focusable targets).
Accessibility
- Focus moves to the summary after a failed submit;
role="alert"announces it. - Every error is a link to its field, and the same message appears at the field (WCAG 3.3.1 / 3.3.3).
- Errors are identified in text — the danger tint and the 4 px danger edge on the start side (design guide §9.2) are not the only signal.
Guidance
Related: Form field · Checkbox / radio group · Alert / banner