Barrierefreie Komponenten · ARIA-Techniken
ARIA: Rollen, States & Properties
ARIA besteht im Kern aus drei Arten von Attributen: Rollen, Zustände und Eigenschaften. Wer diese Dreiteilung einmal verstanden hat, liest ARIA-Markup deutlich entspannter – und setzt es sparsamer und treffsicherer ein. Vorausgesetzt natürlich, man beachtet zuerst die erste Regel von ARIA und greift überhaupt nur dort zu ARIA, wo natives HTML nicht ausreicht.
Am einfachsten merke ich mir die drei so: Die Rolle sagt, was etwas ist. Die Eigenschaft beschreibt eine Beschaffenheit. Der Zustand hält fest, in welcher Verfassung es gerade ist.
Rollen: was ein Element ist
Eine Rolle legt die Bedeutung eines Elements fest – role="tab", role="dialog", role="alert". Sie wird in der Regel einmal gesetzt und ändert sich nicht. Wichtig: Viele Rollen sind in HTML schon eingebaut. Ein <nav> ist eine Navigation, ein <button> ist ein Button – hier ein explizites role zu setzen, ist überflüssig.
<!-- Überflüssig: das Element trägt die Rolle bereits -->
<nav role="navigation">…</nav>
<!-- Sinnvoll: HTML hat dafür kein natives Element -->
<div role="tablist">…</div>
Eine Rolle ist immer ein Versprechen: role="tab" kündigt das Tabs-Verhalten an – inklusive Pfeiltasten-Navigation. Dieses Verhalten musst du dann auch tatsächlich liefern, sonst führt die Rolle in die Irre.
Eigenschaften: stabile Merkmale
Eigenschaften (Properties) beschreiben Merkmale, die sich meist nicht über die Zeit ändern. Die mit Abstand wichtigsten betreffen den zugänglichen Namen und die Beschreibung eines Elements:
| Attribut | Wirkung |
|---|---|
aria-label |
setzt den Namen direkt als Text |
aria-labelledby |
setzt den Namen über die id eines anderen Elements |
aria-describedby |
verknüpft eine ergänzende Beschreibung (z. B. Hilfetext, Fehler) |
aria-controls |
verweist auf das Element, das gesteuert wird |
aria-haspopup |
kündigt ein aufklappbares Element an |
Beim Namen gilt eine feste Rangfolge: aria-labelledby schlägt aria-label, und beide schlagen den sichtbaren Inhalt. Das ist nützlich – aber auch eine Falle, denn ein unbedachtes aria-label kann einen guten sichtbaren Text stillschweigend überschreiben. Ich setze Namen deshalb am liebsten über echtes, sichtbares Markup und greife zu aria-label nur, wenn es sein muss (siehe Labels).
aria-describedby ist die Eigenschaft, die mir im Formularalltag am häufigsten begegnet – sie trägt Hilfetexte und Fehlermeldungen ans Feld.
Zustände: was sich ändert
Zustände (States) beschreiben die aktuelle Verfassung und werden dynamisch aktualisiert, meist per JavaScript. Sie sind das, was während der Bedienung lebt:
| Attribut | Bedeutung |
|---|---|
aria-expanded |
auf-/zugeklappt (Menüs, Akkordeons) |
aria-selected |
ausgewählt (Tabs, Optionen) |
aria-checked |
angehakt (nachgebaute Checkboxen) |
aria-pressed |
gedrückt (Umschalt-Buttons) |
aria-current |
aktuelles Element (aktive Seite, aktueller Schritt) |
aria-invalid |
fehlerhafte Eingabe |
aria-hidden |
vor assistiver Technik verborgen |
Der entscheidende Punkt: Ein Zustand muss mit der Realität synchron bleiben. Klappt ein Akkordeon auf, muss aria-expanded im selben Moment von false auf true springen. Ein Zustand, der hinterherhinkt, ist eine falsche Auskunft – und die ist schlimmer als gar keine.
<button type="button" aria-expanded="false" aria-controls="panel">
Details
</button>
<div id="panel" hidden>…</div>
button.addEventListener('click', () => {
const offen = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!offen));
panel.hidden = offen;
});
Die Grenze ist fließend – und das ist okay
Streng genommen sind Zustand und Eigenschaft technisch beide nur Attribute, und die Spezifikation zieht die Grenze nicht immer scharf. Für die Praxis genügt die Merkhilfe: Ändert sich der Wert während der Bedienung, behandle ihn wie einen Zustand und halte ihn aktuell. Bleibt er konstant, ist es eine Eigenschaft, die du einmal richtig setzt.
Häufige Fehler
- Rolle ohne Verhalten.
role="tab"ohne Tastaturmodell verspricht etwas, das fehlt. - Zustand nicht aktualisiert.
aria-expandedbleibt auffalse, obwohl offen. -
aria-labelüberschreibt sichtbaren Text. Sichtbarer Name und zugänglicher Name sollten übereinstimmen (WCAG 2.5.3). - Redundante Rollen.
role="button"am<button>,role="list"am<ul>– überflüssig. -
aria-describedbyzeigt auf eine fehlendeid. Die Verknüpfung läuft ins Leere.
Häufige Fragen
Woher weiß ich, welche Rolle welche Zustände erwartet?
Aus dem ARIA Authoring Practices Guide. Dort steht für jedes Muster, welche Rollen, Zustände und welches Verhalten zusammengehören – diese Dreiheit ist immer als Paket zu denken.
aria-label oder aria-labelledby?
aria-labelledby, wenn der Name schon als sichtbarer Text auf der Seite steht (dann verweist du darauf). aria-label, wenn es keinen passenden sichtbaren Text gibt. Sichtbarer Text bleibt aber die erste Wahl.
Brauche ich aria-live hier auch?
aria-live ist eine Eigenschaft für sich – sie macht einen Bereich zur Live-Region, deren Änderungen angekündigt werden. Weil das ein eigenes Thema ist, hat es eine eigene Seite.
Fazit
ARIA gliedert sich in Rollen (was etwas ist), Eigenschaften (stabile Merkmale, allen voran der Name) und Zustände (was sich während der Bedienung ändert). Eine Rolle ist ein Versprechen, das Verhalten und aktuell gehaltene Zustände einlösen müssen. Wer diese Aufteilung im Kopf hat, setzt ARIA gezielt ein – und merkt schnell, wie oft gutes natives HTML die halbe Arbeit schon erledigt.