Barrierefreie Formularvalidierung und Fehlermeldungen
A11Y
WCAG
Barrierefreiheit · WCAG · ARIA · Formulare
Barrierefreie Formularvalidierung und Fehlermeldungen
Fehler ankündigen statt nur einfärben

Ein rot umrandetes Eingabefeld nützt Screenreader-Nutzern nichts, wenn der Fehler nicht programmatisch mit dem Feld verknüpft ist. Dieser Artikel zeigt, wie aria-invalid, aria-describedby und Live-Regionen Validierungsfehler zuverlässig ankündigen, inklusive eines vollständigen, barrierefreien Checkout-Beispiels für Magento und Hyvä.

14 Min. Lesezeit aria-invalid · aria-describedby · Live-Region WCAG 2.2 · Magento 2.4.8 · Hyvä Theme

1. Warum Formularvalidierung so oft unzugänglich ist

Formularvalidierung ist einer der Bereiche, in denen Barrierefreiheit am häufigsten scheitert, obwohl der technische Aufwand für eine korrekte Umsetzung gering ist. Das Muster wiederholt sich: Ein Eingabefeld wird rot umrandet, ein Fehlertext erscheint irgendwo auf der Seite, und sehende Nutzer verstehen sofort, was zu tun ist. Screenreader-Nutzer hören davon in der Regel nichts, weil weder der Fehlerstatus noch der Fehlertext programmatisch mit dem betroffenen Feld verbunden sind. Die Seite sieht validiert aus, ist es für assistive Technologien aber nicht.

Das Problem betrifft besonders Checkout-Formulare in Magento-Shops, wo jeder nicht erfassbare Fehler zu einem Kaufabbruch führt. Ein Nutzer mit Screenreader tabbt durch das Formular, drückt auf Absenden, und die Seite scheint einfach nichts zu tun, weil der Fokus nicht zum ersten Fehlerfeld springt und keine Ankündigung erfolgt. Die WCAG 2.2 adressiert genau das mit dem Erfolgskriterium 3.3.1 (Fehlererkennung) und 4.1.3 (Statusmeldungen): Fehler müssen textuell beschrieben und Statusänderungen ohne Fokusverlust angekündigt werden.

Die gute Nachricht: Die Lösung erfordert kein zusätzliches JavaScript-Framework, sondern die korrekte Anwendung von drei ARIA-Attributen und einem semantischen HTML-Grundgerüst. In Hyvä-Themes mit Alpine.js lässt sich das direkt in x-bind-Ausdrücken abbilden, ohne dass ein separates Accessibility-Layer nötig wäre.

2. Warum reine Farbindikatoren scheitern

WCAG-Erfolgskriterium 1.4.1 (Nutzung von Farbe) verlangt, dass Farbe niemals das einzige Mittel ist, um Information zu vermitteln. Ein rot umrandetes Eingabefeld ohne weiteren Hinweis verletzt dieses Kriterium gleich mehrfach: Menschen mit Rot-Grün-Sehschwäche erkennen den Unterschied zwischen normalem und rotem Rahmen oft nicht zuverlässig, Screenreader-Nutzer erhalten überhaupt keine visuelle Information, und Nutzer mit kognitiven Einschränkungen brauchen einen expliziten Text statt einer impliziten Farbkonvention.

Die korrekte Lösung kombiniert immer mindestens drei Signale: eine Textbeschreibung des Fehlers, ein Icon mit ausreichendem Kontrast und semantisch korrektes Markup über aria-invalid. Farbe darf als zusätzliches Signal bestehen bleiben, etwa ein roter Rahmen zur schnellen visuellen Orientierung für sehende Nutzer, aber sie darf nicht das einzige Signal sein. Ein häufiger Fehler in der Praxis: Entwicklerteams fügen zwar einen Fehlertext hinzu, ändern aber nur die Rahmenfarbe des Inputs per CSS-Klasse, ohne diese Klasse mit einem tatsächlichen ARIA-Zustand zu koppeln. Das Ergebnis sieht für sehende Tester korrekt aus, fällt aber bei jedem automatisierten Accessibility-Test wie axe-core oder Lighthouse durch.

Ein zusätzlicher, oft übersehener Aspekt: Der Kontrast des Fehlertexts selbst muss WCAG AA (4.5:1 für normalen Text) erfüllen. Ein zartes Rosa auf weissem Grund wirkt zwar dezent, fällt aber sowohl bei Kontrastprüfungen als auch für Nutzer mit eingeschränktem Sehvermögen durch.

3. aria-invalid: Fehlerstatus programmatisch setzen

Das Attribut aria-invalid="true" teilt assistiven Technologien mit, dass der aktuelle Wert eines Feldes die Validierung nicht besteht. Screenreader wie NVDA oder VoiceOver kündigen beim Fokussieren eines solchen Feldes zusätzlich zum Feldnamen den Status "ungültig" an, sofern das Attribut korrekt gesetzt ist. Wichtig ist, dass aria-invalid dynamisch mit dem tatsächlichen Validierungsstatus synchronisiert wird und nicht permanent im Markup steht, sonst wird jedes Feld dauerhaft als fehlerhaft angekündigt, selbst bei korrekter Eingabe.

Ein zweiter wichtiger Aspekt betrifft den Zeitpunkt, zu dem aria-invalid gesetzt wird. Wird der Fehlerstatus bereits während der ersten Eingabe (bei jedem Tastenanschlag) aktualisiert, hören Screenreader-Nutzer ständig wechselnde Statusmeldungen und empfinden das Formular als unruhig und schwer bedienbar. Die empfohlene Praxis: Validierung erst nach blur (Verlassen des Feldes) oder beim Absenden des Formulars auslösen, danach aber bei jeder weiteren Eingabe live aktualisieren, damit ein Nutzer sofort merkt, wenn der Fehler behoben ist.


<!-- Hyvä phtml: aria-invalid dynamisch über Alpine.js binden -->
<div x-data="{ email: '', touched: false, get emailError() {
  if (!this.touched) return null;
  if (!this.email) return 'E-Mail-Adresse ist erforderlich.';
  if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.email)) return 'Bitte eine gültige E-Mail-Adresse eingeben.';
  return null;
} }">
  <label for="checkout-email" class="block font-semibold mb-1">E-Mail-Adresse</label>
  <input
      id="checkout-email"
      type="email"
      name="email"
      x-model="email"
      @blur="touched = true"
      :aria-invalid="emailError ? 'true' : 'false'"
      :aria-describedby="emailError ? 'checkout-email-error' : null"
      :class="emailError ? 'border-red-600 focus:ring-red-600' : 'border-gray-300 focus:ring-zinc-600'"
      class="w-full rounded-lg border px-3 py-2"
  >
  <p
      x-show="emailError"
      x-text="emailError"
      id="checkout-email-error"
      class="text-red-600 text-sm mt-1"
      role="alert"
  ></p>
</div>

4. aria-describedby: Fehlertext mit dem Feld verknüpfen

Während aria-invalid nur den Status meldet, liefert aria-describedby den eigentlichen Fehlertext. Das Attribut verweist per ID-Referenz auf ein Element mit der Fehlerbeschreibung, und Screenreader lesen diesen Text automatisch vor, sobald das Feld fokussiert wird, direkt im Anschluss an Label und Feldtyp. Entscheidend ist die eindeutige, stabile ID: Jede Fehlermeldung braucht eine eigene ID, die exakt mit dem Wert von aria-describedby im zugehörigen Input übereinstimmt.

Ein häufiger Fehler ist die Verwendung von aria-describedby für Hilfetexte und Fehlermeldungen gleichzeitig über eine feste ID-Liste, ohne zu prüfen, ob das Fehlerelement überhaupt im DOM vorhanden ist. Zeigt aria-describedby auf eine ID, die nicht existiert, ignorieren die meisten Screenreader den gesamten Verweis stillschweigend. Deshalb sollte das Attribut dynamisch gesetzt werden, etwa via :aria-describedby in Alpine.js, sodass es nur dann existiert, wenn das referenzierte Element tatsächlich gerendert ist. Bei mehreren Hinweistexten (Hilfetext plus Fehlermeldung) können mehrere IDs durch Leerzeichen getrennt in einem aria-describedby-Attribut kombiniert werden, etwa aria-describedby="password-hint password-error".


<!-- Kombination aus Hilfetext und Fehlermeldung über mehrere IDs -->
<label for="checkout-password" class="block font-semibold mb-1">Passwort</label>
<p id="password-hint" class="text-sm text-gray-500 mb-1">Mindestens 8 Zeichen, ein Großbuchstabe, eine Zahl.</p>
<input
    id="checkout-password"
    type="password"
    name="password"
    aria-invalid="true"
    aria-describedby="password-hint password-error"
    class="w-full rounded-lg border border-red-600 px-3 py-2"
>
<p id="password-error" role="alert" class="text-red-600 text-sm mt-1 flex items-center gap-1">
  <svg aria-hidden="true" class="w-4 h-4 flex-shrink-0" viewBox="0 0 20 20" fill="currentColor">
    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm-1-9a1 1 0 112 0v4a1 1 0 11-2 0V9zm1-4a1 1 0 100 2 1 1 0 000-2z" clip-rule="evenodd" />
  </svg>
  Das Passwort erfüllt noch nicht alle Anforderungen.
</p>

5. Live-Regionen für die Fehlerzusammenfassung

Bei Formularen mit mehreren Feldern reicht die Verknüpfung einzelner Fehlermeldungen mit ihren Feldern nicht aus, wenn ein Nutzer beim Absenden mehrere Fehler gleichzeitig erzeugt. Eine Live-Region mit role="alert" oder aria-live="assertive" am Anfang des Formulars kündigt eine Zusammenfassung an, sobald die Validierung fehlschlägt: zum Beispiel "3 Fehler gefunden. Bitte E-Mail-Adresse, Passwort und Telefonnummer prüfen." Diese Zusammenfassung wird vom Screenreader sofort vorgelesen, unabhängig davon, wo sich der Fokus gerade befindet.

Wichtig ist der Unterschied zwischen aria-live="polite" und aria-live="assertive": polite wartet, bis der Screenreader eine Sprechpause hat, während assertive laufende Ansagen sofort unterbricht. Für Validierungsfehler beim Formularabsenden ist assertive angemessen, weil der Nutzer unmittelbar informiert werden muss. Für weniger kritische Statusmeldungen, etwa "Warenkorb aktualisiert", ist polite die bessere Wahl, um den Redefluss nicht unnötig zu unterbrechen. Ein zusätzlicher Fallstrick: Eine Live-Region muss bereits beim initialen Seitenaufbau im DOM vorhanden sein (auch wenn leer), da viele Screenreader Änderungen an Elementen, die erst nachträglich mit aria-live versehen werden, nicht zuverlässig erkennen.


// Live-Region für Fehlerzusammenfassung dynamisch befüllen
function announceValidationSummary(errors) {
  const region = document.getElementById('form-error-summary');
  if (!errors.length) {
    region.textContent = '';
    return;
  }
  const fieldNames = errors.map((e) => e.label).join(', ');
  // textContent setzen löst die Live-Region-Ankündigung aus
  region.textContent = `${errors.length} Fehler gefunden. Bitte prüfen: ${fieldNames}.`;

  // Fokus auf die Zusammenfassung setzen, damit sie garantiert wahrgenommen wird
  region.setAttribute('tabindex', '-1');
  region.focus();
}

// Aufruf nach fehlgeschlagener Formularvalidierung
form.addEventListener('submit', (event) => {
  const errors = validateCheckoutForm(form);
  if (errors.length > 0) {
    event.preventDefault();
    announceValidationSummary(errors);
  }
});

6. Fokus-Management nach fehlgeschlagener Validierung

Eine Live-Region allein löst nicht das Problem, dass Tastatur- und Screenreader-Nutzer nach einem gescheiterten Absende-Versuch oft nicht wissen, wo sie als nächstes hinnavigieren sollen. Das empfohlene Pattern: Den Fokus explizit auf das erste fehlerhafte Feld oder auf die Fehlerzusammenfassung setzen, sobald die Validierung fehlschlägt. Bei einer Zusammenfassung mit Sprunglinks zu jedem einzelnen Fehler können Nutzer gezielt zum jeweiligen Feld springen, statt sich durch das gesamte Formular zu tabben.

Ein Element, das per Skript fokussiert werden soll, aber von Natur aus nicht fokussierbar ist (wie ein div oder p), braucht tabindex="-1", damit element.focus() überhaupt funktioniert. Ohne dieses Attribut ignoriert der Browser den Fokus-Aufruf stillschweigend. Wichtig: tabindex="-1" nimmt das Element nicht in die normale Tab-Reihenfolge auf, erlaubt aber die programmatische Fokussierung per JavaScript, genau das richtige Verhalten für eine Fehlerzusammenfassung, die kein interaktives Steuerelement ist.

7. Praxisbeispiel: Alpine.js-Validierung in Hyvä

In Hyvä-Themes übernimmt Alpine.js die clientseitige Validierungslogik, ohne zusätzliche Bibliotheken wie jQuery Validation zu benötigen. Der Schlüssel zu barrierefreier Alpine-Validierung liegt darin, ARIA-Attribute konsequent an denselben reaktiven Zustand zu binden wie die visuelle Darstellung, statt zwei getrennte Wahrheiten zu pflegen. Ein zentrales errors-Objekt im x-data-Scope, aus dem sowohl CSS-Klassen als auch aria-invalid und aria-describedby abgeleitet werden, verhindert, dass visueller und semantischer Zustand auseinanderlaufen.

Ein weiterer Vorteil von Alpine.js in diesem Kontext: x-effect lässt sich nutzen, um bei jeder Änderung des Fehlerzustands automatisch die Live-Region zu aktualisieren, ohne manuelles DOM-Handling. Das hält die gesamte Validierungslogik deklarativ und in einer einzigen Datei, was gerade in Hyvä-Templates, die ohnehin auf minimales JavaScript setzen, konsistent zum restlichen Ansatz des Themes passt.


// Zentrales errors-Objekt: einzige Quelle für visuellen und semantischen Zustand
function checkoutValidation() {
  return {
    fields: { email: '', telephone: '' },
    errors: {},
    validateField(name) {
      if (name === 'email' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.fields.email)) {
        this.errors.email = 'Gültige E-Mail-Adresse eingeben.';
      } else {
        delete this.errors.email;
      }
      if (name === 'telephone' && !/^\+?[0-9\s-]{6,}$/.test(this.fields.telephone)) {
        this.errors.telephone = 'Gültige Telefonnummer eingeben.';
      } else {
        delete this.errors.telephone;
      }
    },
    // x-effect ruft diese Methode bei jeder Änderung von errors auf
    syncLiveRegion() {
      const region = document.getElementById('live-error-count');
      const count = Object.keys(this.errors).length;
      region.textContent = count > 0 ? `${count} Fehler im Formular.` : '';
    }
  };
}

8. Vollständiges Checkout-Validierungsbeispiel

Das folgende Beispiel kombiniert alle bisherigen Bausteine in einem realistischen Checkout-Ausschnitt mit drei Feldern: Vorname, E-Mail-Adresse und Postleitzahl. Es zeigt Live-Region, Fehlerzusammenfassung mit Sprunglinks, individuelle Feldverknüpfung über aria-describedby und Fokus-Management nach dem Absenden in einer zusammenhängenden Alpine.js-Komponente.

Bemerkenswert an diesem Muster: Es kommt vollständig ohne zusätzliche Accessibility-Bibliothek aus. Alle notwendigen Zustände (welches Feld ungültig ist, welcher Text angezeigt wird, wohin der Fokus springt) werden aus einem einzigen reaktiven Alpine-Objekt abgeleitet. Das reduziert das Risiko, dass visuelle und semantische Zustände bei zukünftigen Änderungen auseinanderlaufen, ein Risiko, das bei getrennter jQuery- und CSS-Logik deutlich höher ist.


<!-- Hyvä phtml: vollständiges, barrierefreies Checkout-Validierungsbeispiel -->
<form
    x-data="{
      fields: { firstname: '', email: '', postcode: '' },
      errors: {},
      submitted: false,
      validate() {
        this.errors = {};
        if (!this.fields.firstname.trim()) this.errors.firstname = 'Vorname ist erforderlich.';
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(this.fields.email)) this.errors.email = 'Gültige E-Mail-Adresse eingeben.';
        if (!/^\d{5}$/.test(this.fields.postcode)) this.errors.postcode = 'Postleitzahl muss 5 Ziffern haben.';
        return Object.keys(this.errors).length === 0;
      },
      onSubmit() {
        this.submitted = true;
        if (!this.validate()) {
          this.$nextTick(() => this.$refs.summary.focus());
        } else {
          this.$refs.form.submit();
        }
      }
    }"
    x-ref="form"
    @submit.prevent="onSubmit()"
>
  <!-- Live-Region: wird bei jedem gescheiterten Absenden neu vorgelesen -->
  <div
      x-ref="summary"
      x-show="submitted && Object.keys(errors).length > 0"
      role="alert"
      aria-live="assertive"
      tabindex="-1"
      class="border border-red-600 bg-red-50 rounded-lg p-4 mb-6"
  >
    <p class="font-semibold text-red-700" x-text="`${Object.keys(errors).length} Fehler gefunden. Bitte prüfen:`"></p>
    <ul class="mt-2 space-y-1">
      <template x-for="(message, field) in errors" :key="field">
        <li><a :href="`#checkout-${field}`" class="text-red-700 underline" x-text="message"></a></li>
      </template>
    </ul>
  </div>

  <div class="mb-4">
    <label for="checkout-firstname" class="block font-semibold mb-1">Vorname</label>
    <input
        id="checkout-firstname"
        x-model="fields.firstname"
        :aria-invalid="errors.firstname ? 'true' : 'false'"
        :aria-describedby="errors.firstname ? 'checkout-firstname-error' : null"
        class="w-full rounded-lg border px-3 py-2"
        :class="errors.firstname ? 'border-red-600' : 'border-gray-300'"
    >
    <p x-show="errors.firstname" id="checkout-firstname-error" x-text="errors.firstname" class="text-red-600 text-sm mt-1"></p>
  </div>

  <div class="mb-4">
    <label for="checkout-email" class="block font-semibold mb-1">E-Mail-Adresse</label>
    <input
        id="checkout-email"
        type="email"
        x-model="fields.email"
        :aria-invalid="errors.email ? 'true' : 'false'"
        :aria-describedby="errors.email ? 'checkout-email-error' : null"
        class="w-full rounded-lg border px-3 py-2"
        :class="errors.email ? 'border-red-600' : 'border-gray-300'"
    >
    <p x-show="errors.email" id="checkout-email-error" x-text="errors.email" class="text-red-600 text-sm mt-1"></p>
  </div>

  <div class="mb-6">
    <label for="checkout-postcode" class="block font-semibold mb-1">Postleitzahl</label>
    <input
        id="checkout-postcode"
        x-model="fields.postcode"
        :aria-invalid="errors.postcode ? 'true' : 'false'"
        :aria-describedby="errors.postcode ? 'checkout-postcode-error' : null"
        class="w-full rounded-lg border px-3 py-2"
        :class="errors.postcode ? 'border-red-600' : 'border-gray-300'"
    >
    <p x-show="errors.postcode" id="checkout-postcode-error" x-text="errors.postcode" class="text-red-600 text-sm mt-1"></p>
  </div>

  <button type="submit" class="bg-zinc-800 text-white font-semibold px-6 py-3 rounded-lg">Bestellung abschließen</button>
</form>

9. Formularvalidierung im direkten Vergleich

Die folgende Tabelle stellt verbreitete, unzugängliche Validierungsmuster den korrekten, barrierefreien Alternativen gegenüber. Der Unterschied liegt selten in zusätzlichem Aufwand, sondern in der korrekten Verknüpfung von visuellem und semantischem Zustand.

Aufgabe Unzugänglich Barrierefrei Vorteil
Fehler anzeigen Nur roter Rahmen per CSS-Klasse aria-invalid="true" + Text + Icon Screenreader erkennt Status und Ursache
Fehlertext platzieren Text irgendwo im Formular ohne Verknüpfung aria-describedby verweist auf Fehler-ID Text wird automatisch beim Feld vorgelesen
Absenden mit Fehlern Seite bleibt scheinbar untätig Live-Region kündigt Fehlerzahl an Sofortige, unmissverständliche Rückmeldung
Nach Fehlschlag navigieren Fokus bleibt auf Submit-Button Fokus springt zu Zusammenfassung/Feld Kein manuelles Durchtabben nötig
Live-Update während Eingabe aria-invalid bei jedem Tastenanschlag Validierung erst nach blur/Submit Keine ständig wechselnden Ansagen

In der Praxis ergänzen sich die fünf Zeilen der Tabelle gegenseitig: Ein korrektes aria-invalid ohne verknüpften Fehlertext ist ebenso unvollständig wie eine Live-Region ohne anschliessendes Fokus-Management. Erst das Zusammenspiel aller Bausteine macht ein Formular für Screenreader-Nutzer tatsächlich bedienbar.

Mironsoft

Barrierefreiheit, WCAG-Audits und zugängliche Hyvä-Komponenten

Checkout-Formulare wirklich barrierefrei machen?

Wir prüfen eure Magento- und Hyvä-Formulare gegen WCAG 2.2, identifizieren fehlende ARIA-Verknüpfungen und setzen aria-invalid, aria-describedby und Live-Regionen so um, dass Screenreader-Nutzer Fehler zuverlässig erfassen.

Formular-Audit

Screenreader-Test mit NVDA/VoiceOver und automatisierter axe-core-Analyse

ARIA-Refactoring

aria-invalid, aria-describedby und Live-Regionen in Alpine.js-Komponenten nachrüsten

Checkout-Optimierung

Fokus-Management und Fehlerzusammenfassungen für geringere Kaufabbrüche

10. Zusammenfassung

Barrierefreie Formularvalidierung löst ein konkretes Problem: Screenreader-Nutzer müssen Fehler ohne visuelle Hinweise vollständig erfassen können. aria-invalid="true" markiert den Fehlerstatus programmatisch am betroffenen Feld. aria-describedby verknüpft die konkrete Fehlermeldung per ID-Referenz mit dem Input, sodass sie beim Fokussieren automatisch vorgelesen wird. Eine Live-Region mit role="alert" kündigt beim Absenden eine Zusammenfassung an, unabhängig vom aktuellen Fokus. Fokus-Management nach gescheiterter Validierung führt Nutzer gezielt zum ersten Fehler oder zur Zusammenfassung, statt sie durch das gesamte Formular tabben zu lassen.

Keines dieser Muster erfordert zusätzliche Bibliotheken. In Hyvä-Themes lassen sich alle vier Bausteine direkt in Alpine.js-Komponenten abbilden, wenn ARIA-Attribute konsequent an denselben reaktiven Zustand gebunden werden wie die visuelle Darstellung. Wer Farbe niemals als alleiniges Fehlersignal nutzt und stattdessen Text, Icon und ARIA-Zustand kombiniert, erfüllt gleichzeitig WCAG 1.4.1, 3.3.1 und 4.1.3 und reduziert nachweislich Kaufabbrüche im Checkout.

Barrierefreie Formularvalidierung, das Wichtigste auf einen Blick

aria-invalid

Fehlerstatus programmatisch am Feld setzen, dynamisch nach blur oder Submit, niemals permanent im Markup.

aria-describedby

Fehlertext per stabiler ID mit dem Feld verknüpfen, damit Screenreader ihn automatisch vorlesen.

Live-Region

role="alert" für die Fehlerzusammenfassung beim Absenden, bereits im initialen DOM vorhanden.

Fokus-Management

Fokus nach gescheiterter Validierung explizit auf Zusammenfassung oder erstes Fehlerfeld setzen.

11. FAQ: Barrierefreie Formularvalidierung und Fehlermeldungen

1Warum reicht ein roter Rahmen bei einem fehlerhaften Feld nicht aus?
Rein visuelles Signal, Screenreader-Nutzer erhalten nichts davon mit, Rot-Grün-Sehschwäche erschwert die Erkennung. WCAG 1.4.1 verlangt zusätzlich Text, Icon und aria-invalid.
2Was macht aria-invalid genau?
Markiert ein Feld programmatisch als fehlerhaft. Screenreader kündigen beim Fokussieren den Status ungültig an. Muss dynamisch mit dem echten Validierungsstatus synchron bleiben.
3Wie verknüpfe ich eine Fehlermeldung korrekt mit einem Feld?
Über aria-describedby mit ID-Referenz auf das Fehlerelement. Die ID muss eindeutig sein und exakt übereinstimmen, sonst wird der Verweis ignoriert.
4Wann assertive statt polite für aria-live?
assertive unterbricht sofort, passend für Validierungsfehler beim Absenden. polite wartet auf eine Sprechpause und eignet sich für weniger dringende Meldungen.
5Warum funktioniert element.focus() manchmal nicht?
div oder p sind von Natur aus nicht fokussierbar. tabindex=-1 macht sie per Skript fokussierbar, ohne sie in die Tab-Reihenfolge aufzunehmen.
6Sollte Validierung bei jedem Tastenanschlag laufen?
Nein, das erzeugt unruhige Ansagen. Validierung nach blur oder Submit auslösen, danach live aktualisieren, sobald der Fehler behoben wird.
7Muss eine Live-Region schon beim Laden im DOM stehen?
Ja. Viele Screenreader erkennen Änderungen nur zuverlässig, wenn aria-live schon beim initialen Rendern vorhanden ist, nicht erst nachträglich eingefügt.
8Wie setze ich das in Hyvä mit Alpine.js um?
Über ein zentrales errors-Objekt in x-data, aus dem CSS-Klassen und ARIA-Attribute gleichzeitig abgeleitet werden. Keine zusätzliche Bibliothek nötig.
9Welche WCAG-Kriterien betrifft das konkret?
Vor allem 1.4.1, 3.3.1, 3.3.3 und 4.1.3. Zusammen verlangen sie textuelle, programmatisch verknüpfte und live angekündigte Fehlerinformationen.
10Wie teste ich Formularvalidierung auf Barrierefreiheit?
Automatisiert mit axe-core/Lighthouse für strukturelle Probleme, manuell mit NVDA oder VoiceOver bei ausgeschaltetem Monitor für echtes Nutzererlebnis.