Mehrstufige Formulare und Fortschrittsanzeigen barrierefrei gestalten
AI generated
A11Y
WCAG
Barrierefreiheit · Formulare · Wizard-Pattern
Mehrstufige Formulare barrierefrei
fieldset pro Schritt, aria-current im Stepper und verlustfreie Zurück-Navigation im Wizard-Pattern

Ein mehrstufiges Formular ist mehr als eine Aneinanderreihung einzelner Formularseiten: Es braucht eine erkennbare Gruppierung pro Schritt, eine Fortschrittsanzeige, die den aktuellen Schritt eindeutig kommuniziert, eine aktive Ankündigung jedes Schrittwechsels für Screenreader-Nutzer und eine Zurück-Navigation, die eingegebene Daten zuverlässig erhält. Dieses allgemeine Wizard-Pattern gilt für Registrierungsassistenten, mehrstufige Konfiguratoren und Umfragen genauso wie für jeden anderen mehrstufigen Formularprozess abseits des Checkouts.

10 Min. Lesezeit aria-current=step Wizard-Pattern allgemein

1. Das Wizard-Pattern als eigenständiges, allgemeines Problem

Mehrstufige Formulare treten in sehr unterschiedlichen Kontexten auf: Registrierungsassistenten mit mehreren Profil-Schritten, Produktkonfiguratoren mit aufeinander aufbauenden Auswahlschritten, mehrseitige Umfragen oder Support-Formulare mit bedingter Verzweigung. All diese Fälle teilen dieselbe technische Grundstruktur unabhängig vom konkreten Checkout-Kontext, weshalb sich das Wizard-Pattern als eigenständiges, wiederverwendbares Barrierefreiheitsthema behandeln lässt.

Vier Bausteine treten dabei immer wieder auf und müssen unabhängig voneinander korrekt umgesetzt werden: die semantische Gruppierung der Felder innerhalb eines Schritts, die visuelle und semantische Fortschrittsanzeige über alle Schritte hinweg, die aktive Ankündigung eines Schrittwechsels und der verlustfreie Umgang mit bereits eingegebenen Daten bei Vor- und Zurück-Navigation.

2. fieldset und legend: Gruppierung der Formularfelder pro Schritt

Jeder einzelne Schritt eines mehrstufigen Formulars sollte als eigenes fieldset-Element ausgezeichnet werden, mit einer legend, die den Zweck dieses Schritts kurz zusammenfasst, etwa "Schritt 2 von 4: Kontaktdaten". Diese Gruppierung ist mehr als reine Kosmetik, sie sorgt dafür, dass ein Screenreader beim Fokussieren des ersten Feldes im Schritt automatisch den Kontext des gesamten Schritts mit ansagt, nicht nur das einzelne Feldlabel.

Ohne fieldset/legend muss ein Nutzer sich den aktuellen Schritt-Kontext allein aus einzelnen Feldlabels erschließen, was besonders bei ähnlich benannten Feldern in verschiedenen Schritten, etwa mehreren Adressfeldern in unterschiedlichen Kontexten, schnell zu Verwechslungen führt.


<fieldset class="wizard-step" data-step="2">
  <legend>Schritt 2 von 4: Kontaktdaten</legend>

  <label for="email">E-Mail-Adresse</label>
  <input type="email" id="email" name="email" required>

  <label for="phone">Telefonnummer</label>
  <input type="tel" id="phone" name="phone">
</fieldset>

3. Progress-Stepper Markup: aria-current für den aktuellen Schritt

Die Fortschrittsanzeige selbst wird üblicherweise als nav-Element mit einer geordneten Liste ol umgesetzt, in der jedes li einen Schritt repräsentiert. Der aktuell aktive Schritt bekommt das Attribut aria-current="step", einen speziellen, für genau diesen Anwendungsfall vorgesehenen Wert von aria-current, der sich von den generischeren Werten page oder true unterscheidet und Screenreadern explizit mitteilt, dass es sich um einen Schritt in einem sequenziellen Prozess handelt.

Bereits abgeschlossene Schritte sollten sich visuell und semantisch von noch nicht erreichten Schritten unterscheiden, etwa über einen zusätzlichen, versteckten Text wie "abgeschlossen" oder "noch nicht erreicht" innerhalb jedes Listenelements. Dieser Status darf nicht ausschließlich über eine Häkchen-Grafik oder eine Farbänderung kommuniziert werden, da beides ohne begleitenden Text für Screenreader unsichtbar bleibt.


<nav aria-label="Fortschritt">
  <ol class="stepper">
    <li>
      <span class="sr-only">Abgeschlossen: </span>Konto
    </li>
    <li aria-current="step">
      <span class="sr-only">Aktueller Schritt: </span>Kontaktdaten
    </li>
    <li>
      <span class="sr-only">Noch nicht erreicht: </span>Adresse
    </li>
    <li>
      <span class="sr-only">Noch nicht erreicht: </span>Bestätigung
    </li>
  </ol>
</nav>

4. Screenreader-Ankündigung von Schrittwechseln

Wechselt der Nutzer per Weiter-Button von einem Schritt zum nächsten, ändert sich in einer typischen Single-Page-Wizard-Implementierung nur der sichtbare Inhalt im DOM, ohne dass ein vollständiger Seitenwechsel stattfindet. Ohne aktive Ankündigung bemerkt ein Screenreader-Nutzer diesen Wechsel unter Umständen gar nicht, weil der Fokus an derselben Stelle verbleibt, an der sich zuvor der Weiter-Button befand.

Eine aria-live="polite"-Region, die bei jedem Schrittwechsel einen kurzen Text wie "Schritt 3 von 4: Adresse" ausgibt, macht den Wechsel zuverlässig hörbar. Diese Ankündigung ersetzt nicht das Fokus-Management aus dem nächsten Abschnitt, sondern ergänzt es, weil eine Live-Region auch dann wirkt, wenn der Fokus aus technischen Gründen kurzzeitig nicht exakt gesetzt werden kann.


<div id="step-announcement" class="sr-only" aria-live="polite"></div>

<script>
function goToStep(stepNumber, stepLabel, totalSteps) {
  document.getElementById('step-announcement').textContent =
    'Schritt ' + stepNumber + ' von ' + totalSteps + ': ' + stepLabel;
}
</script>

5. Fokus-Management beim Schrittwechsel: Fokus auf die Schritt-Überschrift setzen

Zusätzlich zur Live-Region-Ankündigung sollte der Tastaturfokus beim Schrittwechsel aktiv auf die Überschrift oder die legend des neuen Schritts gesetzt werden, meist per tabindex="-1" plus .focus() in JavaScript, da nicht-interaktive Elemente wie Überschriften standardmäßig nicht fokussierbar sind. Dieser Schritt stellt sicher, dass Tastaturnutzer nach dem Wechsel unmittelbar am Anfang des neuen Schritt-Inhalts weiterarbeiten können, statt manuell dorthin navigieren zu müssen.

Bleibt der Fokus stattdessen auf dem Weiter-Button des vorherigen Schritts stehen, der im neuen Schritt gar nicht mehr existiert oder an anderer Stelle liegt, verliert der Nutzer die Orientierung und muss den kompletten neuen Formularinhalt erst mit der Tab-Taste durchsuchen, um herauszufinden, was sich verändert hat.


function focusStepHeading(stepEl) {
  const heading = stepEl.querySelector('legend, h2');
  if (heading) {
    heading.setAttribute('tabindex', '-1');
    heading.focus();
  }
}

6. Validierung pro Schritt vor dem Weiterschalten und Fehlerzusammenfassung

Ein Weiter-Klick sollte den aktuellen Schritt zunächst vollständig validieren, bevor zum nächsten Schritt gewechselt wird. Treten Fehler auf, darf der Schrittwechsel nicht stattfinden, und der Fokus muss auf eine Fehlerzusammenfassung am Anfang des aktuellen Schritts gesetzt werden, die alle fehlerhaften Felder als Liste mit Sprunglinks zum jeweiligen Feld aufführt.

Diese Fehlerzusammenfassung folgt demselben Muster wie bei einer einstufigen Formularvalidierung, wird hier aber pro Schritt wiederholt angewendet, da jeder Schritt faktisch ein eigenständiger Validierungsabschnitt ist. Wichtig ist, dass die Fehlermeldung eindeutig macht, in welchem Schritt der Fehler liegt, besonders wenn später eine Zusammenfassungsseite über alle Schritte hinweg Fehler sammelt.

7. Zwischenspeichern und Zurück-Navigation ohne Datenverlust

Navigiert ein Nutzer per Zurück-Button oder über einen klickbaren Schritt im Stepper zu einem vorherigen Schritt zurück, müssen bereits eingegebene Werte dort weiterhin vorhanden sein. Technisch lässt sich das entweder über einen clientseitigen State-Speicher, etwa einen Alpine-Store oder sessionStorage, oder über ein serverseitiges Zwischenspeichern bei jedem Schrittwechsel lösen, wobei Letzteres zusätzlich vor Datenverlust bei einem versehentlichen Browser-Neuladen schützt.

Aus Barrierefreiheitssicht ist entscheidend, dass die Zurück-Navigation keinen kompletten Neustart des Formulars auslöst, sondern exakt zum vorherigen Zustand samt aller eingegebenen Werte zurückkehrt, inklusive korrekt gesetztem Fokus auf die Schritt-Überschrift und korrekt aktualisiertem aria-current im Stepper. Ein Nutzer, der versehentlich einen Schritt zurückgeht, darf nicht dafür bestraft werden, bereits eingegebene Daten erneut eintippen zu müssen.


document.addEventListener('alpine:init', () => {
  Alpine.data('wizard', () => ({
    currentStep: 1,
    values: Alpine.$persist({}).as('wizard-values'),
    goTo(step) {
      this.currentStep = step;
      this.$nextTick(() => focusStepHeading(this.$refs['step-' + step]));
    },
  }));
});

8. Klickbare vs. reine Anzeige-Steps: aria-disabled für nicht erreichte Schritte

Ob Nutzer im Stepper direkt zu einem späteren, noch nicht erreichten Schritt springen dürfen, hängt vom jeweiligen Anwendungsfall ab. Ist ein direkter Sprung nicht sinnvoll, weil der spätere Schritt von Daten aus einem früheren, noch nicht validierten Schritt abhängt, sollte der entsprechende Stepper-Eintrag mit aria-disabled="true" markiert werden, statt ihn einfach optisch auszugrauen, ohne das semantisch zu kommunizieren.

Bereits abgeschlossene, frühere Schritte sollten dagegen fast immer klickbar bleiben, da Nutzer häufig noch einmal zurückspringen wollen, um eine Eingabe zu korrigieren. Ein klickbarer, bereits abgeschlossener Schritt-Eintrag sollte als button oder a-Element umgesetzt werden, nicht als reines li mit einem Klick-Handler ohne native interaktive Semantik.

9. Umsetzung in Magento und Hyvä: generische Alpine.js-Wizard-Komponente

Da das Wizard-Pattern nicht auf den Checkout beschränkt ist, lohnt sich eine generische Alpine.js-Komponente, die Schrittzustand, Validierung pro Schritt, Fokus-Management und die aria-live-Ankündigung kapselt und sich sowohl für einen Registrierungsassistenten als auch für einen Produktkonfigurator oder ein mehrstufiges Kontaktformular wiederverwenden lässt. Die konkreten Formularfelder je Schritt bleiben dabei austauschbar, während die Barrierefreiheitslogik zentral an einer Stelle gepflegt wird.

Jeder inline eingebundene script-Block für Fokus-Management oder Schrittwechsel-Ankündigung muss über $hyvaCsp->registerInlineScript() im jeweiligen phtml-Template registriert werden, damit die Content Security Policy die Ausführung nicht blockiert.


<div x-data="wizard" x-cloak>
  <nav aria-label="Fortschritt">
    <ol class="stepper">
      <template x-for="(step, index) in steps" :key="step.id">
        <li :aria-current="currentStep === index + 1 ? 'step' : null">
          <span x-text="step.label"></span>
        </li>
      </template>
    </ol>
  </nav>

  <div id="step-announcement" class="sr-only" aria-live="polite" x-text="announcement"></div>
</div>
Baustein Technik Zweck Häufiger Fehler
Feldgruppierung fieldset plus legend pro Schritt Kontext beim Fokussieren automatisch mit ansagen Nur einzelne Feldlabels ohne Gruppen-Kontext
Fortschrittsanzeige aria-current=step im Stepper Aktuellen Schritt eindeutig kennzeichnen Nur visuelle Hervorhebung ohne ARIA
Schrittwechsel aria-live Region mit Schritt-Ansage Wechsel ohne Seitenneuladen hörbar machen Stiller DOM-Wechsel ohne Ankündigung
Fokus nach Wechsel Fokus auf Überschrift des neuen Schritts Direktes Weiterarbeiten ermöglichen Fokus bleibt auf verschwundenem Button
Zurück-Navigation State-Speicher pro Schritt Eingegebene Werte erhalten Formular startet beim Zurückgehen neu

Mironsoft

WCAG-Audits, barrierefreie Magento-Shops und Schulungen

Unsicher, ob der Shop wirklich barrierefrei ist?

Wir prüfen bestehende Magento-Shops gegen WCAG 2.2, beheben konkrete Barrieren im Hyvä-Frontend und schulen Teams, damit Barrierefreiheit dauerhaft im Entwicklungsprozess verankert bleibt.

WCAG-Audit

Shop systematisch gegen WCAG 2.2 AA prüfen, mit priorisierter Fehlerliste.

Barrieren beheben

Konkrete Umsetzung: Tastaturbedienbarkeit, Screenreader-Support, Kontraste, Formulare.

Team-Schulung

Entwickler und Redakteure für barrierefreie Umsetzung im Alltag sensibilisieren.

10. Zusammenfassung

Mehrstufige Formulare barrierefrei: Die wichtigsten Fragen

Grundprinzip

fieldset und legend pro Schritt liefern automatisch Kontext, sobald ein Nutzer das erste Feld eines Schritts fokussiert.

Fortschrittsanzeige

aria-current=step markiert den aktuellen Schritt semantisch eindeutig, zusätzlich zu jeder visuellen Hervorhebung.

Schrittwechsel

Eine aria-live Ankündigung plus gezieltes Fokus-Management auf die neue Schritt-Überschrift machen jeden Wechsel nachvollziehbar.

Datenerhalt

Zurück-Navigation darf niemals bereits eingegebene Werte verwerfen, unabhängig davon, ob client- oder serverseitig gespeichert wird.

11. FAQ: Mehrstufige Formulare barrierefrei: Die wichtigsten Fragen

1Warum sollte jeder Schritt eines Wizards ein eigenes fieldset bekommen?
Damit ein Screenreader beim Fokussieren des ersten Feldes automatisch den Kontext des gesamten Schritts über die legend mit ansagt.
2Was bedeutet aria-current=step im Progress-Stepper?
Es ist ein spezieller Wert von aria-current, der explizit einen Schritt in einem sequenziellen Prozess kennzeichnet, anders als die generischeren Werte page oder true.
3Reicht eine farbliche Hervorhebung des aktuellen Schritts im Stepper aus?
Nein, ohne aria-current und begleitenden Text bleibt der Status für Screenreader unsichtbar, Farbe allein ist nicht ausreichend.
4Wie erfahren Screenreader-Nutzer von einem Schrittwechsel ohne Seitenneuladen?
Über eine aria-live=polite Region, die bei jedem Wechsel einen kurzen Text mit Schrittnummer und Bezeichnung ausgibt.
5Wohin sollte der Fokus nach einem Schrittwechsel gesetzt werden?
Auf die Überschrift oder legend des neuen Schritts, meist per tabindex=-1 und focus() in JavaScript, da Überschriften standardmäßig nicht fokussierbar sind.
6Was passiert, wenn Validierungsfehler beim Weiterschalten auftreten?
Der Schrittwechsel darf nicht stattfinden, stattdessen wird der Fokus auf eine Fehlerzusammenfassung mit Sprunglinks zu den fehlerhaften Feldern gesetzt.
7Wie verhindere ich Datenverlust bei der Zurück-Navigation?
Über clientseitigen State wie einen Alpine-Store oder sessionStorage, alternativ serverseitiges Zwischenspeichern bei jedem Schrittwechsel.
8Sollten alle Schritte im Stepper klickbar sein?
Bereits abgeschlossene Schritte fast immer, noch nicht erreichte Schritte nur, wenn kein Datenabhängigkeitsproblem besteht, sonst mit aria-disabled markieren.
9Ist das Wizard-Pattern nur für den Checkout relevant?
Nein, es gilt genauso für Registrierungsassistenten, Produktkonfiguratoren, Umfragen und jedes andere mehrstufige Formular.
10Reicht eine Live-Region allein, ohne zusätzliches Fokus-Management?
Nein, beide ergänzen sich: die Live-Region sichert die Ansage ab, das Fokus-Management ermöglicht direktes Weiterarbeiten am neuen Schritt.