Suchfeld und Autocomplete-Vorschläge barrierefrei implementieren
AI generated
A11Y
WCAG
Barrierefreiheit · Suchfeld · ARIA-Combobox
Suchfeld und Autocomplete-Vorschläge barrierefrei implementieren
Das ARIA-Combobox-Pattern korrekt und ohne Fokus-Chaos umsetzen

Ein Suchfeld mit Live-Vorschlägen sieht für sehende Nutzer selbsterklärend aus, ist aber ohne das ARIA-Combobox-Pattern für Tastatur- und Screenreader-Nutzer oft schlicht unbedienbar.

10 Min. Lesezeit role=combobox aria-activedescendant Live-Suche

1. Warum klassische Such-Widgets das ARIA-Combobox-Pattern brauchen

Ein einfaches Textfeld mit einer darunter eingeblendeten Vorschlagsliste sieht für sehende Nutzer wie ein zusammenhängendes Element aus. Technisch handelt es sich jedoch um zwei getrennte DOM-Bausteine, ein input-Element und eine Liste, deren Beziehung ohne zusätzliche ARIA-Attribute für Screenreader nicht erkennbar ist.

Ohne das Combobox-Pattern erfährt ein Screenreader-Nutzer nicht, dass beim Tippen neue Vorschläge erscheinen, kann diese nicht sinnvoll durchsuchen und weiß nicht, welcher Vorschlag gerade als aktiv markiert ist. Das Ergebnis ist ein Suchfeld, das rein visuell funktioniert, aber für einen ganzen Teil der Nutzerschaft unbrauchbar bleibt.

Das W3C ARIA Authoring Practices Guide definiert für genau diesen Fall das Combobox-Pattern mit einer festen Rollenstruktur. Es lohnt sich, dieses Pattern exakt zu befolgen, statt eine eigene Variante zu entwickeln, da Screenreader ihre Ansagen genau auf diese Struktur abstimmen.

2. Grundstruktur: role="combobox", aria-expanded, aria-controls

Das Eingabefeld selbst erhält role="combobox", auch wenn es sich technisch um ein normales input-Element handelt. Zusätzlich zeigt aria-expanded an, ob die Vorschlagsliste gerade sichtbar ist, und aria-controls verweist auf die id der Liste, damit die Beziehung zwischen beiden Elementen für Screenreader eindeutig ist.

Die Vorschlagsliste selbst erhält role="listbox", jeder einzelne Vorschlag darin role="option". Diese Struktur ist unabhängig davon einzuhalten, ob die Liste als ul, div oder eigene Komponente gerendert wird, solange die ARIA-Rollen konsistent gesetzt sind.

Ein häufiger Fehler ist, aria-expanded dauerhaft auf true zu setzen oder komplett wegzulassen, weil die Liste ohnehin per CSS ein- und ausgeblendet wird. Screenreader verlassen sich jedoch auf den ARIA-Zustand, nicht auf die visuelle Sichtbarkeit, weshalb beide synchron gehalten werden müssen.


<label for="site-search">Suche</label>
<input
  type="text"
  id="site-search"
  role="combobox"
  aria-expanded="false"
  aria-controls="site-search-listbox"
  aria-autocomplete="list"
  autocomplete="off"
>
<ul id="site-search-listbox" role="listbox" hidden>
  <li role="option" id="option-1">Herrenjacke Winter</li>
  <li role="option" id="option-2">Herrenhose Cargo</li>
</ul>

3. aria-activedescendant statt Fokus-Verschiebung

Beim Navigieren durch die Vorschlagsliste mit den Pfeiltasten bleibt der tatsächliche Tastaturfokus im input-Element. Statt den Fokus auf jede einzelne Option zu verschieben, wird über aria-activedescendant auf dem input-Element mitgeteilt, welche Option gerade als aktiv gilt.

Dieses Muster hat einen entscheidenden Vorteil gegenüber echter Fokus-Verschiebung: Der Nutzer kann jederzeit weitertippen, ohne den Fokus erst wieder ins Eingabefeld zurückholen zu müssen. Bei einer echten Fokus-Verschiebung auf jede Option würde jeder Tastendruck den Fokus unerwartet zurück ins Feld springen lassen.

Die aktive Option muss zusätzlich visuell hervorgehoben werden, meist über eine eigene CSS-Klasse, die parallel zum aria-activedescendant-Wert per JavaScript gesetzt wird. Nur die Kombination aus visueller und programmatischer Markierung macht die Auswahl für sehende und blinde Nutzer gleichermaßen nachvollziehbar.


let activeIndex = -1;
const options = Array.from(listbox.querySelectorAll('[role="option"]'));

function setActiveOption(index) {
  options.forEach((el) => el.classList.remove('bg-slate-100'));
  activeIndex = index;
  if (index >= 0) {
    options[index].classList.add('bg-slate-100');
    input.setAttribute('aria-activedescendant', options[index].id);
  } else {
    input.removeAttribute('aria-activedescendant');
  }
}

4. Pfeiltasten-Navigation durch die Vorschläge implementieren

Die Tastatursteuerung folgt einem festen, dokumentierten Muster: Pfeil-runter bewegt die aktive Auswahl zur nächsten Option, Pfeil-hoch zur vorherigen, Enter übernimmt die aktive Option in das Eingabefeld, und Escape schließt die Liste, ohne eine Auswahl zu übernehmen.

Am unteren und oberen Ende der Liste sollte die Navigation entweder stoppen oder zum jeweils anderen Ende umspringen, konsistent mit dem Verhalten, das Screenreader-Nutzer aus nativen Auswahlfeldern kennen. Ein plötzliches Verschwinden der Auswahl am Listenende wirkt dagegen wie ein Programmfehler.

Die Tab-Taste sollte die Liste dabei niemals zum Navigieren verwenden, sondern ausschließlich zum Verlassen des gesamten Suchfelds dienen, wie bei jedem anderen Formularelement auch. Wird Tab für die Listennavigation zweckentfremdet, bricht das die Erwartungshaltung aller Tastaturnutzer, nicht nur die von Screenreader-Nutzern.


input.addEventListener('keydown', (event) => {
  switch (event.key) {
    case 'ArrowDown':
      event.preventDefault();
      setActiveOption(Math.min(activeIndex + 1, options.length - 1));
      break;
    case 'ArrowUp':
      event.preventDefault();
      setActiveOption(Math.max(activeIndex - 1, 0));
      break;
    case 'Enter':
      if (activeIndex >= 0) {
        input.value = options[activeIndex].textContent;
        closeListbox();
      }
      break;
    case 'Escape':
      closeListbox();
      break;
  }
});

5. Screenreader-Ansage der Trefferanzahl

Neben der einzelnen Navigation durch Vorschläge ist auch die Gesamtzahl der Treffer eine wichtige Information, die sehende Nutzer visuell sofort erfassen, Screenreader-Nutzer aber aktiv mitgeteilt bekommen müssen. Ohne diese Information bleibt unklar, ob überhaupt Ergebnisse existieren oder ob das Laden noch läuft.

Eine separate, dezente Live-Region, unabhängig von der eigentlichen Vorschlagsliste, eignet sich dafür besser als eine Ansage direkt in der Listbox selbst. Eine Meldung wie „5 Treffer gefunden“ oder „Keine Treffer gefunden“ reicht als aria-live="polite"-Ansage vollständig aus.

Wichtig ist, diese Ansage erst nach Abschluss der Suche auszulösen, nicht bei jedem einzelnen Tastendruck während des Tippens. Ein serverseitiges Debounce von 200 bis 300 Millisekunden verhindert sowohl unnötige Serveranfragen als auch eine Flut von Zwischenansagen, die den eigentlichen Suchvorgang akustisch überlagern würden.


// Live-Region im Markup: <div aria-live="polite" class="sr-only" data-search-status></div>
function updateResultCount(count) {
  const status = document.querySelector('[data-search-status]');
  status.textContent = count === 0
    ? 'Keine Treffer gefunden.'
    : `${count} Treffer gefunden.`;
}

6. Suchbegriff-Highlighting ohne Screenreader-Rauschen

Das visuelle Hervorheben des gesuchten Begriffs innerhalb der Vorschläge, meist über ein strong- oder mark-Element, ist für sehende Nutzer eine hilfreiche Orientierung. Screenreader lesen mark-Elemente standardmäßig ohne besondere Betonung vor, was in den meisten Fällen auch der richtige Umgang damit ist.

Problematisch wird es, wenn zusätzlich versucht wird, die Hervorhebung akustisch nachzubilden, etwa durch eingefügte Symbole oder wiederholte Ansagen des hervorgehobenen Textteils. Das führt zu unnötig langen, schwer verständlichen Ansagen und sollte vermieden werden.

Ein sinnvoller Kompromiss ist, das Highlighting rein visuell zu belassen und stattdessen die Gesamtzahl der Treffer sowie eine klare Struktur der einzelnen Optionen für die akustische Wahrnehmung zu optimieren, statt zu versuchen, jedes visuelle Detail eins zu eins akustisch nachzubilden.

7. Abgrenzung zu Datepicker- und klassischen Combobox-Patterns

Das Suchfeld-Pattern mit Live-Vorschlägen unterscheidet sich von klassischen Auswahl-Comboboxen und Datepickern vor allem darin, dass freier Text eingegeben werden kann, der nicht zwingend einem Vorschlag entsprechen muss. Bei einer klassischen Combobox oder einem Datepicker ist meist genau ein gültiger Wert aus einer festen Menge zu wählen.

Diese Unterscheidung wirkt sich direkt auf aria-autocomplete aus: Suchfelder mit freien Texteingaben verwenden meist aria-autocomplete="list", während strengere Auswahlfelder mit automatischer Vervollständigung eher aria-autocomplete="both" nutzen, was zusätzlich einen Inline-Vervollständigungsvorschlag im Eingabefeld selbst ermöglicht.

Ein eigener Artikel dieser Reihe behandelt barrierefreie Datepicker und klassische Comboboxen im Detail, inklusive deren spezifischer Tastatursteuerung für Datumsauswahl. Wer beide Pattern verwechselt und identisch implementiert, produziert für Nutzer verwirrende Erwartungsabweichungen, etwa wenn Enter bei einer Suche unerwartet ein Formular komplett absendet statt nur die Auswahl zu übernehmen.

Die Hyvä-Live-Search-Komponente basiert typischerweise auf Alpine.js und einem debounced Fetch-Aufruf gegen die Magento-Such-API. Für eine barrierefreie Umsetzung müssen die ARIA-Attribute des Combobox-Patterns parallel zum bestehenden x-show/x-model-Zustand gepflegt werden, nicht als nachträglicher Zusatz.

Ein praktikabler Ansatz ist, die aria-expanded- und aria-activedescendant-Werte direkt aus denselben Alpine.js-Datenpunkten abzuleiten, die auch die sichtbare Darstellung steuern, statt eine parallele, potenziell inkonsistente zweite Zustandsverwaltung aufzubauen.

Die serverseitige Trefferanzahl aus der Magento-Such-API lässt sich direkt in die separate Live-Region für die Ansage übernehmen, ohne zusätzliche Logik im Frontend, da die API diese Zahl ohnehin für die Anzeige der Ergebnisse bereits mitliefert.


<div x-data="liveSearch()" class="relative">
  <input
    type="text"
    role="combobox"
    :aria-expanded="open ? 'true' : 'false'"
    aria-controls="live-search-listbox"
    :aria-activedescendant="activeId"
    x-model="query"
    @input.debounce.250ms="search()"
    @keydown.arrow-down.prevent="moveActive(1)"
    @keydown.arrow-up.prevent="moveActive(-1)"
    @keydown.enter="selectActive()"
    @keydown.escape="close()"
  >
  <ul id="live-search-listbox" role="listbox" x-show="open">
    <template x-for="(result, index) in results" :key="result.id">
      <li role="option" :id="'option-' + result.id" x-text="result.name"></li>
    </template>
  </ul>
  <div aria-live="polite" class="sr-only" x-text="statusMessage"></div>
</div>

9. Häufige Fehler bei Autocomplete-Implementierungen

Der wohl verbreitetste Fehler ist, die Vorschlagsliste komplett ohne ARIA-Rollen als reines div mit Klick-Handlern zu bauen. Visuell funktioniert das einwandfrei, für Tastatur- und Screenreader-Nutzer bleibt die Liste jedoch faktisch unsichtbar und unbedienbar.

Ein zweiter häufiger Fehler ist, beim Öffnen der Liste den echten Fokus auf die erste Option zu verschieben, statt aria-activedescendant zu verwenden. Das unterbricht die Texteingabe sofort, da der Fokus das input-Element verlässt, sobald ein Vorschlag erscheint.

Ein dritter Fehler ist eine fehlende oder falsch synchronisierte aria-expanded-Angabe, die dazu führt, dass Screenreader eine Liste ankündigen, obwohl sie visuell längst geschlossen ist, oder umgekehrt eine geöffnete Liste komplett verschweigen. Beide Fälle wirken für Nutzer stark irritierend und untergraben das Vertrauen in die Ansagen des Screenreaders.

ARIA-Attribut Position Zweck Häufiger Fehler
role="combobox" input-Element Kennzeichnet das Feld als erweiterbare Eingabe Fehlt komplett oder auf falschem Element gesetzt
aria-expanded input-Element Zeigt Sichtbarkeit der Vorschlagsliste an Nicht synchron mit tatsächlicher CSS-Sichtbarkeit
aria-activedescendant input-Element Markiert aktuell aktive Option Fehlt, Fokus wird stattdessen verschoben
role="listbox" Container der Vorschläge Kennzeichnet die Liste als Auswahlmenge Container bleibt ohne Rolle als reines div
role="option" Einzelner Vorschlag Kennzeichnet einen wählbaren Eintrag Fehlende eindeutige id für aria-activedescendant

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

Suchfeld-Autocomplete

Grundstruktur

role="combobox" auf dem Eingabefeld, role="listbox" und role="option" für die Vorschlagsliste konsequent setzen.

Aktive Auswahl

aria-activedescendant statt echter Fokus-Verschiebung verwenden, damit die Texteingabe nicht unterbrochen wird.

Trefferanzahl

Ergebniszahl über eine separate, gedrosselte aria-live-Region ansagen, nicht bei jedem Tastendruck.

Abgrenzung

Freitext-Suchfelder mit aria-autocomplete="list" von strengeren Auswahl-Comboboxen mit "both" unterscheiden.

11. FAQ: Suchfeld-Autocomplete

1Warum reicht ein normales input-Feld mit CSS-Dropdown nicht aus?
Weil die Beziehung zwischen Eingabefeld und Vorschlagsliste ohne ARIA-Attribute für Screenreader nicht erkennbar ist. Ohne role="combobox" und zugehörige Attribute bleibt das Suchfeld für Tastatur- und Screenreader-Nutzer faktisch unbedienbar.
2Was ist der Unterschied zwischen aria-activedescendant und echter Fokus-Verschiebung?
aria-activedescendant markiert eine Option als aktiv, ohne den tatsächlichen Tastaturfokus zu verändern. So kann der Nutzer weitertippen, während echte Fokus-Verschiebung den Fokus bei jeder Navigation aus dem Eingabefeld herausbewegen würde.
3Wie zeige ich Screenreader-Nutzern die Trefferanzahl an?
Über eine separate aria-live="polite"-Region mit einer kurzen Meldung wie 5 Treffer gefunden, die erst nach Abschluss der Suche aktualisiert wird, nicht bei jedem Tastendruck.
4Sollte ich das Highlighting des Suchbegriffs auch akustisch nachbilden?
Nein, das führt zu unnötig langen und schwer verständlichen Ansagen. Das Highlighting bleibt rein visuell, während die Gesamtzahl der Treffer für die akustische Wahrnehmung wichtiger ist.
5Was bedeutet aria-autocomplete="list" im Unterschied zu "both"?
list zeigt nur eine Liste von Vorschlägen an, both ermöglicht zusätzlich eine automatische Inline-Vervollständigung direkt im Eingabefeld, was eher bei strengeren Auswahlfeldern sinnvoll ist.
6Wie unterscheidet sich das Suchfeld-Pattern von einem Datepicker?
Suchfelder erlauben freien Text, der keinem Vorschlag entsprechen muss, während Datepicker und klassische Comboboxen meist genau einen gültigen Wert aus einer festen Menge erwarten.
7Warum sollte Tab nicht zur Navigation in der Vorschlagsliste verwendet werden?
Weil Tab bei allen Formularelementen konsistent zum Verlassen des Feldes dient. Wird Tab zweckentfremdet, widerspricht das der Erwartungshaltung aller Tastaturnutzer.
8Wie oft sollte die Suche während des Tippens ausgelöst werden?
Mit einem Debounce von etwa 200 bis 300 Millisekunden, um unnötige Serveranfragen und eine Flut von Zwischenansagen zu vermeiden.
9Muss die Vorschlagsliste zwingend als ul umgesetzt werden?
Nein, entscheidend sind die ARIA-Rollen listbox und option, nicht das konkrete HTML-Element. Auch ein div mit den passenden Rollen funktioniert korrekt.
10Was ist der häufigste Fehler bei selbst gebauten Autocomplete-Feldern?
Die Vorschlagsliste komplett ohne ARIA-Rollen als reines div mit Klick-Handlern zu bauen, was visuell funktioniert, für Tastatur- und Screenreader-Nutzer aber unbedienbar bleibt.