- 12. Mai 2026
#lessonlearned – Accordion-Accessibility: WAI-ARIA-Pattern in HeadlessUI nachrüsten
Barrierefreiheit zeigt sich oft nicht in großen Umbauten, sondern in den kleinen technischen Details einer Komponente. Gerade interaktive Elemente wie Accordions müssen für Screenreader, Tastaturnavigation und assistive Technologien sauber ausgezeichnet sein. In diesem Lesson Learned zeigen wir, wie wir die Barrierefreiheit von Accordion-Komponenten in unserer Nuxt-Anwendung verbessert haben, obwohl die zugrunde liegende UI-Bibliothek das benötigte WAI-ARIA-Pattern nicht vollständig abgebildet hat.

Warum Accordions bei der Barrierefreiheit besonders wichtig sind
Accordions werden häufig für FAQs, Key Facts oder strukturierte Inhaltsblöcke eingesetzt. Für sehende Benutzer wirken sie oft unproblematisch, weil das Verhalten visuell klar ist: Ein Bereich wird geöffnet oder geschlossen.
Für Screenreader gilt das jedoch nur dann, wenn die semantischen Beziehungen zwischen Auslöser und Inhalt technisch korrekt gesetzt sind. Fehlen diese Informationen, wird der Zusammenhang zwischen Button und zugehörigem Inhaltsbereich nicht sauber vermittelt.
Genau das war in unserem Fall die Herausforderung.
Die Ausgangssituation mit HeadlessUI
In unserem Projekt kam die Disclosure-Komponente von HeadlessUI zum Einsatz, unter anderem über UAccordion. Diese Komponente bringt bereits einige wichtige ARIA-Attribute mit:
aria-expandedauf dem Buttonaria-controlsals Verweis auf das zugehörige Panel
Das ist eine gute Grundlage, reicht aber für das vollständige WAI-ARIA-Accordion-Pattern noch nicht aus. Uns fehlten vor allem zwei Dinge:
role="region"auf dem Inhaltsbereicharia-labelledbyauf dem Panel mit Verweis auf den auslösenden Button
Ohne diese Ergänzungen können Screenreader den geöffneten Bereich nicht immer eindeutig dem zugehörigen Trigger zuordnen.
Unser Ansatz: fehlende Attribute gezielt ergänzen
Da wir die Bibliothek selbst nicht umbauen wollten, haben wir uns für einen pragmatischen Weg entschieden: ein wiederverwendbares Composable, das nach dem Rendern die fehlenden Attribute ergänzt.
Ein vereinfachter Ausschnitt sieht so aus:
// app/composables/useAccordionA11y.ts
export function useAccordionA11y(containerRef: Ref<HTMLElement | null>) {
const enhance = () => {
const container = containerRef.value
if (!container) return
const buttons = container.querySelectorAll(
'[id^="headlessui-disclosure-button"]'
)
buttons.forEach((btn) => {
const panelId = btn.getAttribute('aria-controls')
if (panelId) {
const panel = document.getElementById(panelId)
if (panel && !panel.getAttribute('aria-labelledby')) {
panel.setAttribute('role', 'region')
panel.setAttribute('aria-labelledby', btn.id)
}
}
})
}
onMounted(() => nextTick(enhance))
return { enhance }
}ts
Die Idee dahinter ist einfach: Nach dem Einhängen der Komponente prüfen wir die bereits von HeadlessUI erzeugte Struktur und ergänzen genau die Attribute, die für die bessere Zugänglichkeit noch fehlen.
Einbindung in die betroffenen Komponenten
Das Composable kann überall dort verwendet werden, wo UAccordion eingesetzt wird. Dadurch bleibt die Lösung wiederverwendbar und muss nicht für jede einzelne Komponente neu umgesetzt werden.
<script setup lang="ts">
const faqRef = ref<HTMLElement | null>(null)
const { enhance: enhanceA11y } = useAccordionA11y(faqRef)
</script>
<template>
<div ref="faqRef" class="sb-faq">
<UAccordion :items="items">
<!-- Slots -->
</UAccordion>
</div>
</template>Vue
Auf diese Weise lässt sich die Ergänzung sehr gezielt an den Stellen einsetzen, an denen sie benötigt wird.
Weitere Accessibility-Verbesserungen im selben Zuge
Im Zuge dieser Überarbeitung haben wir nicht nur die Accordions selbst betrachtet, sondern auch weitere kleinere Auffälligkeiten in angrenzenden Komponenten korrigiert.
Interaktive Elemente als Button statt Link auszeichnen
Ein Beispiel war die Funktion „Alle Fragen anzeigen“. Technisch wurde sie zunächst als Link umgesetzt, obwohl sie keine Navigation auslöst, sondern eine Aktion innerhalb der Seite.
Vorher:
<a class="sb-load-all" @click="loadAllItems">Alle Fragen anzeigen</a>HTML
Nachher:
<button class="sb-load-all" type="button" @click="loadAllItems">
Alle Fragen anzeigen
</button>HTML
Das verbessert die Bedienbarkeit per Tastatur und macht die Funktion auch semantisch korrekt.
Dekorative Icons vor Screenreadern verbergen
Icons, die rein dekorativ sind, sollten nicht vorgelesen werden. Deshalb haben wir diese mit aria-hidden="true" versehen.
<span class="icon icon-arrow-head-down" aria-hidden="true"></span>HTML
Symbol-Links mit sprechenden Bezeichnungen versehen
Bei reinen Icon-Links, etwa im Footer für soziale Netzwerke, braucht es eine verständliche Beschriftung für Screenreader.
<a href="..." aria-label="LinkedIn" rel="noopener noreferrer" target="_blank">
<span class="icon-linkedin" aria-hidden="true"></span>
</a>HTML
So bleibt die Oberfläche auch für Benutzer verständlich, die die Symbole nicht visuell erfassen.
Was sich für uns bewährt hat
Im Projekt hat sich vor allem gezeigt, dass man sich bei UI-Bibliotheken nicht allein auf die Dokumentation verlassen sollte.
Tatsächliche Ausgabe im Browser prüfen
Auch wenn eine Komponente als zugänglich beschrieben wird, lohnt sich der Blick in den gerenderten HTML-Code. Gerade bei ARIA-Attributen zeigt sich dort schnell, ob wirklich alles vorhanden ist.
Kleine Ergänzungen können große Wirkung haben
In unserem Fall war kein kompletter Umbau nötig. Schon das gezielte Ergänzen weniger Attribute hat die semantische Qualität deutlich verbessert.
Accessibility ganzheitlich betrachten
Wenn man eine Komponente ohnehin überarbeitet, lohnt sich meist auch der Blick auf angrenzende Details wie Buttons, Links oder Icons. Oft lassen sich mehrere Verbesserungen in einem Schritt umsetzen.
Unser wichtigstes Aha
Unser wichtigstes Learning war, dass auch etablierte UI-Bibliotheken nicht automatisch jedes Accessibility-Muster vollständig umsetzen. Für uns war deshalb entscheidend, die tatsächliche ARIA-Ausgabe im Browser zu prüfen und fehlende Informationen gezielt zu ergänzen.
Mit einem wiederverwendbaren Composable konnten wir das WAI-ARIA-Pattern für unsere Accordion-Komponenten sinnvoll erweitern und gleichzeitig weitere kleine Verbesserungen in angrenzenden Elementen umsetzen. So entstand mit überschaubarem Aufwand eine deutlich zugänglichere Lösung.