Feedbackstable.alert
Alert / banner
A message box that is part of the page and stays: information, success, a warning or an error, with an optional next step.
Use alerts for things that remain true while the page is open: "Anmeldung offen bis 31. Oktober", "3 Bewerbende ohne Gebühr", "Webling ist gerade nicht erreichbar". For short confirmations of what just happened use a toast; for field errors use the form field and error summary.
The tone sets colour and icon and is written as data-status: info (default), neutral, success, warning, danger. Look (design guide §9.4): subtle status background, a 4 px status-fill edge on the start side, status icon (20 px) and title in the status text colour, body in --color-text. The title says what is going on in one line; the body says what it means and what to do. Offer the next step as a link or one action button.
Page-level banners (offline, lock, impersonation) sit directly below the top bar, full width and without radius: add data-banner to the element (page code; render produces the in-page form). The connection banner is its own component (Offline banner).
Errors follow UX guide §7.3: a human message, what happened, what to do — never raw HTTP codes or provider messages. Show the trace id small and selectable (traceId) so support can find the case.
role="status" (default) is announced politely; use role: "alert" only for urgent errors that appear after a user action. Alerts present when the page loads are not announced either way — they are read in page order.
Examples
Info
Anmeldung offen bis 31. Oktober
Danach erstellt das System die Prüfungsgruppen automatisch.
Data
render({
"title": "Anmeldung offen bis 31. Oktober",
"body": "Danach erstellt das System die Prüfungsgruppen automatisch."
})Markup
<div class="alert" role="status"><svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#info"/></svg><div class="alert__body">
<p class="alert__title">Anmeldung offen bis 31. Oktober</p>
<p>Danach erstellt das System die Prüfungsgruppen automatisch.</p>
</div></div>Success
12 Gurtgrade in Webling gespeichert
Data
render({
"tone": "success",
"title": "12 Gurtgrade in Webling gespeichert"
})Markup
<div class="alert" data-status="success" role="status"><svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#check-circle"/></svg><div class="alert__body">
<p class="alert__title">12 Gurtgrade in Webling gespeichert</p>
</div></div>Warning with link
3 Bewerbende ohne Gebühr
Ohne Gebühr können keine Rechnungen erstellt werden. Gebühren festlegen
Data
render({
"tone": "warning",
"title": "3 Bewerbende ohne Gebühr",
"body": "Ohne Gebühr können keine Rechnungen erstellt werden.",
"link": {
"href": "/belt-tests/2026-11/fees",
"label": "Gebühren festlegen"
}
})Markup
<div class="alert" data-status="warning" role="status"><svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#alert-triangle"/></svg><div class="alert__body">
<p class="alert__title">3 Bewerbende ohne Gebühr</p>
<p>Ohne Gebühr können keine Rechnungen erstellt werden. <a href="/belt-tests/2026-11/fees">Gebühren festlegen</a></p>
</div></div>Error with retry and trace id
Webling ist gerade nicht erreichbar
Deine Änderungen sind gespeichert und werden übertragen, sobald Webling wieder antwortet.
Fehler-ID: tr-8f2a
Data
render({
"tone": "danger",
"role": "alert",
"title": "Webling ist gerade nicht erreichbar",
"body": "Deine Änderungen sind gespeichert und werden übertragen, sobald Webling wieder antwortet.",
"action": {
"action": "retry",
"label": "Erneut versuchen"
},
"traceId": "tr-8f2a"
})Markup
<div class="alert" data-status="danger" role="alert"><svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#alert-circle"/></svg><div class="alert__body">
<p class="alert__title">Webling ist gerade nicht erreichbar</p>
<p>Deine Änderungen sind gespeichert und werden übertragen, sobald Webling wieder antwortet.</p>
<p class="u-small">Fehler-ID: <code>tr-8f2a</code></p>
<div class="button-row" data-align="start"><button class="button" type="button" data-size="sm" data-action="retry">Erneut versuchen</button></div>
</div></div>Neutral note
Dieses Training wurde aus der Vorlage «Kinder Dienstag» erstellt.
Data
render({
"tone": "neutral",
"title": "Dieses Training wurde aus der Vorlage «Kinder Dienstag» erstellt."
})Markup
<div class="alert" data-status="neutral" role="status"><svg class="icon" aria-hidden="true"><use href="../../packages/ui/icons/icons.svg#info"/></svg><div class="alert__body">
<p class="alert__title">Dieses Training wurde aus der Vorlage «Kinder Dienstag» erstellt.</p>
</div></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 |
|---|---|---|---|---|
tone | "info" | "neutral" | "success" | "warning" | "danger" | optional | "info" | Meaning; sets colour and icon. |
title | string | required | — | One-line summary ("Webling ist gerade nicht erreichbar"). min 1 chars |
body | string | optional | — | What it means and what to do, one or two sentences. |
link | object | optional | — | Optional link to the next step, appended to the body. |
link.href | string | required | — | Link target URL. |
link.label | string | required | — | Link text naming the step ("Gebühren festlegen"). min 1 chars |
action | object | optional | — | Optional button for an in-place action (e.g. "Erneut versuchen"); the page handles clicks via data-action. |
action.action | string | required | — | Action key written to data-action ("retry").pattern ^[a-z][a-z0-9-]*$ |
action.label | string | required | — | Button text, a verb ("Erneut versuchen"). min 1 chars |
traceId | string | optional | — | Support/trace id for errors, shown small as "Fehler-ID: …". |
role | "status" | "alert" | optional | "status" | Live-region role: alert only for urgent errors after a user action. |
JSON Schema
{
"type": "object",
"additionalProperties": false,
"required": [
"title"
],
"properties": {
"tone": {
"type": "string",
"enum": [
"info",
"neutral",
"success",
"warning",
"danger"
],
"default": "info",
"description": "Meaning; sets colour and icon."
},
"title": {
"type": "string",
"minLength": 1,
"description": "One-line summary (\"Webling ist gerade nicht erreichbar\")."
},
"body": {
"type": "string",
"description": "What it means and what to do, one or two sentences."
},
"link": {
"type": "object",
"additionalProperties": false,
"required": [
"href",
"label"
],
"description": "Optional link to the next step, appended to the body.",
"properties": {
"href": {
"type": "string",
"description": "Link target URL."
},
"label": {
"type": "string",
"minLength": 1,
"description": "Link text naming the step (\"Gebühren festlegen\")."
}
}
},
"action": {
"type": "object",
"additionalProperties": false,
"required": [
"action",
"label"
],
"description": "Optional button for an in-place action (e.g. \"Erneut versuchen\"); the page handles clicks via `data-action`.",
"properties": {
"action": {
"type": "string",
"pattern": "^[a-z][a-z0-9-]*$",
"description": "Action key written to `data-action` (\"retry\")."
},
"label": {
"type": "string",
"minLength": 1,
"description": "Button text, a verb (\"Erneut versuchen\")."
}
}
},
"traceId": {
"type": "string",
"description": "Support/trace id for errors, shown small as \"Fehler-ID: …\"."
},
"role": {
"type": "string",
"enum": [
"status",
"alert"
],
"default": "status",
"description": "Live-region role: `alert` only for urgent errors after a user action."
}
}
}Markup & states
Root: div.alert — usable without render() by writing the markup directly.
Attributes
| Attribute | Values | Default | Description |
|---|---|---|---|
data-status | neutral | success | warning | danger | (none = info) | Status: background, edge, icon and title colour. |
data-banner | — | — | Page-level banner below the top bar: no radius (set by page code). |
role | status | alert | — | Live-region politeness. |
Parts
| Part | Description |
|---|---|
.alert > svg.icon | Status icon, 20 px, in the status text colour (decorative): info · check-circle · alert-triangle · alert-circle. |
.alert__body | Text column. |
.alert__title | Semibold first line in the status text colour. |
.alert__body > p | Body text in --color-text; links inherit it. |
.button-row | Optional action button. |
Behaviour & events
Module: (page code)
No built-in behaviour. Handle the optional action with a delegated listener on [data-action].
Events
| Event | Detail | Description |
|---|---|---|
click on [data-action] | event.target.closest("[data-action]").dataset.action | The action button was pressed. |
Accessibility
- Meaning is carried by the title text, not only by colour or icon.
role="status"for most alerts;role="alert"only for urgent errors inserted after an action.- The trace id is real text, selectable for copying.
Guidance
Related: Toast · Offline banner · Error summary · Empty state