Kundenansicht neu E-Fix M3: Fehlermeldungen der Bestellseiten und Formulare als Live-Region (role="alert")

abo-error, switch-error (und der Fehler der Wechsel-Vorschau), storage-error, tk-error samt Fehlerzeile der Rückfrage-Antwort, der Fehler von
"Zahlungsart aktualisieren" sowie login-error und form-error auf Login, Kündigen und Widerrufen waren einfache Absätze: Screenreader lasen
sie nicht vor, obwohl der Knopf wieder frei wurde. Jetzt role="alert", gepinnt in test/knEfixCss.test.js.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-16 21:42:07 +00:00
1 parent ddaf2879c4
commit 4c64edc057
9 files changed
+32 -10

No files matched your search

+1 -1
View File
@@ -99,7 +99,7 @@ function bestellung(daten, productKey, { viewAs, kundenart }) {
], { id: 'abo-einzelheiten' })
const haken = privat ? h('input', { type: 'checkbox', id: 'abo-beginn', disabled: viewAs }) : null
const fehler = h('p', { class: K.fehler, id: 'abo-error', hidden: true })
const fehler = h('p', { class: K.fehler, id: 'abo-error', role: 'alert', hidden: true })
const kaufen = h('button', { type: 'button', class: K.primaer, id: 'abo-buy', disabled: viewAs }, T.knopf || KNOPF)
const zeigeFehler = (text) => { fehler.textContent = text; fehler.hidden = false }
+2 -2
View File
@@ -77,7 +77,7 @@ function antragsFormular(grenzen, email, T) {
h('p', { class: 'kn-hinweis' }, 'Tipp: Lade auch die Kündigungsbestätigung deines bisherigen Anbieters hoch – daraus sehen wir, wann der Vertrag dort endet.'),
feld('E-Mail-Adresse für unsere Antwort', h('input', { id: 'tk-email', class: K.input, type: 'email', maxlength: 255, autocomplete: 'email', value: email })),
baueLinkzeile(T.gutschrift.satz, { id: 'tk-satz', neuerTab: true }),
h('p', { class: K.fehler, id: 'tk-error', hidden: true }),
h('p', { class: K.fehler, id: 'tk-error', role: 'alert', hidden: true }),
h('div', { class: 'kn-aktionen' },
h('button', { type: 'submit', class: K.primaer, id: 'tk-submit' }, T.gutschrift.knopf || 'Antrag absenden'),
h('button', { type: 'button', class: K.knopf, id: 'tk-cancel' }, 'Abbrechen')))
@@ -102,7 +102,7 @@ function antrag(r, viewAs) {
h('form', { class: 'kn-tk-antwort', 'data-reply-for': r.id, novalidate: true },
h('textarea', { name: 'message', class: K.textarea, maxlength: 4000, placeholder: 'Deine Antwort…' }),
h('input', { type: 'file', name: 'files', accept: 'application/pdf,image/jpeg,image/png', multiple: true, 'aria-label': 'Weitere Nachweise' }),
h('p', { class: K.fehler, hidden: true }),
h('p', { class: K.fehler, role: 'alert', hidden: true }),
h('div', { class: 'kn-aktionen' }, h('button', { type: 'submit', class: K.primaer, disabled: viewAs }, 'Antwort senden')))]
} else {
koerper = [h('p', { class: 'kn-hinweis' }, 'Wir prüfen deine Angaben und antworten dir per E-Mail.')]
+1 -1
View File
@@ -75,7 +75,7 @@ function baueSpeicherPanel(daten, { viewAs, kundenart, notice, nachErfolg }) {
summary = h('div', { class: 'kn-speicher-zusammenfassung kn-bestellen' },
baueBlock(zeilen, { id: 'storage-block' }),
plus ? baueLinkzeile(T.speicher.linkzeile, { id: 'storage-linkzeile' }) : baueLinkzeile(T.speicher.warnung, { id: 'storage-warnung', klasse: 'kn-speicher-warnung' }),
h('p', { class: 'kn-fehler', id: 'storage-error', hidden: !fehlerText }, fehlerText),
h('p', { class: 'kn-fehler', id: 'storage-error', role: 'alert', hidden: !fehlerText }, fehlerText),
h('div', { class: 'kn-aktionen' },
h('button', { type: 'button', class: K.primaer, id: 'storage-submit', disabled: Boolean(gesperrt), on: { click: absenden } }, state.busy ? 'Wird gespeichert …' : plus ? (T.knopf || KNOPF) : 'Speichern')),
plus ? baueKundenartZeile(kundenart, T.kundenart, { id: 'storage-kundenart' }) : null)
+2 -2
View File
@@ -114,7 +114,7 @@ export async function zeigeWechsel(wurzel, { route, me, nav, daten } = {}) {
const zeichne = () => {
const p = lauf.preview
const uebersicht = lauf.error
? h('p', { class: K.fehler }, lauf.error)
? h('p', { class: K.fehler, role: 'alert' }, lauf.error)
: lauf.loading || !p ? h('p', { class: 'kn-hinweis' }, 'Deine Übersicht wird berechnet …')
: baueBlock(zeilenVon(p), { id: 'switch-block' })
const sperre = lauf.busy || viewAs
@@ -131,7 +131,7 @@ export async function zeigeWechsel(wurzel, { route, me, nav, daten } = {}) {
baueLinkzeile(T.wechsel.linkzeile, { id: 'switch-linkzeile' }),
haken ? h('label', { class: K.check }, haken, h('span', { id: 'switch-beginn-text' }, T.wechsel.haken)) : null,
gesperrt ? h('p', { class: 'kn-sperrzeile', id: 'switch-sperre' }, T.wechsel.gesperrt) : null,
h('p', { class: lauf.fehlerKlasse ?? K.fehler, id: 'switch-error', hidden: !lauf.fehler }, lauf.fehler),
h('p', { class: lauf.fehlerKlasse ?? K.fehler, id: 'switch-error', role: 'alert', hidden: !lauf.fehler }, lauf.fehler),
h('div', { class: 'kn-aktionen' },
h('button', { type: 'button', class: K.primaer, id: 'switch-buy', disabled: lauf.busy || viewAs || lauf.loading || !p || gesperrt, on: { click: absenden } }, lauf.busy ? 'Wird bestellt …' : (T.knopf || KNOPF)),
viewAs ? h('span', { class: K.meldung }, TEXT_SPERRE) : null),
+1 -1
View File
@@ -55,7 +55,7 @@
<input type="date" id="effective-date" class="hidden">
</fieldset>
<p class="kn-fehlertext hidden" id="form-error"></p>
<p class="kn-fehlertext hidden" id="form-error" role="alert"></p>
<button type="submit" class="kn-absenden">Jetzt kündigen</button>
</form>
+1 -1
View File
@@ -54,7 +54,7 @@
autocomplete="current-password"
enterkeyhint="go"
>
<p id="login-error" class="kn-fehlertext hidden"></p>
<p id="login-error" class="kn-fehlertext hidden" role="alert"></p>
<!-- Mitarbeiter-Login ist gesperrt: Link ins Ticketsystem (Adresse aus der Antwort, ticketUrl) -->
<a id="login-staff-link" class="kn-login-staff hidden" href="https://ticket.webklar.com">Zum Ticketsystem</a>
<button type="submit" id="login-btn" class="kn-login-knopf">
+1 -1
View File
@@ -44,7 +44,7 @@
<label for="email" data-label-for="email" data-label="E-Mail für die Eingangsbestätigung">E-Mail-Adresse <small>(dorthin schicken wir die Eingangsbestätigung)</small></label>
<input id="email" name="email" type="email" autocomplete="email" required maxlength="255">
<p class="kn-fehlertext hidden" id="form-error"></p>
<p class="kn-fehlertext hidden" id="form-error" role="alert"></p>
<button type="submit" class="kn-absenden">Widerruf bestätigen</button>
</form>
+1 -1
View File
@@ -53,7 +53,7 @@ const fakt = (titel, wert) => h('div', null, h('dt', null, titel), h('dd', null,
// "Zahlungsart aktualisieren": Stripe-Kundenportal; im Ansichtsmodus gesperrt
function zahlungsKnopf(viewAs) {
const fehler = h('p', { class: K.fehler, hidden: true })
const fehler = h('p', { class: K.fehler, role: 'alert', hidden: true })
const knopf = h('button', { type: 'button', class: K.primaer, disabled: viewAs }, 'Zahlungsart aktualisieren')
knopf.addEventListener('click', async () => {
if (viewAs) return