Een ontwikkelaarsgids voor ARIA-labels die echt helpen
ARIA-labels zijn geen magische toegankelijkheidslaag. Goed gebruikt maken ze bedieningselementen begrijpelijk. Achteloos gebruikt verbergen ze nuttige tekst en zorgen ze voor verwarrende interfaces.
Inhoudsopgave
- ARIA-labels zijn voor namen, niet voor excuses
- De toegankelijke naam, in gewone taal
- Eerste regel: geef de voorkeur aan native HTML en zichtbare labels
- Wanneer `aria-label` het juiste hulpmiddel is
- Wanneer `aria-label` het verkeerde hulpmiddel is
- Grijp naar `aria-labelledby` wanneer zichtbare tekst al bestaat
- Gebruik `aria-describedby` voor hulptekst, niet voor de naam
- Herhaalde bedieningselementen hebben unieke namen nodig
- Label niet alles
- Controleer de berekende naam, niet alleen de code
- Een praktische reviewchecklist
- De stille discipline van goede ARIA
ARIA-labels zijn voor namen, niet voor excuses
ARIA is nuttig, maar wordt vaak gebruikt als pleister voor onduidelijke HTML. Daar komen teams in de problemen.
Het meest voorkomende voorbeeld is aria-label. Het lijkt onschuldig: voeg een string toe, stel een linter tevreden, en ga door. Maar een toegankelijke naam is geen decoratie. Het is de naam die veel ondersteunende technologieën aan gebruikers tonen wanneer zij navigeren langs knoppen, links, formuliervelden, koppen, landmarks en bedieningselementen.
Als die naam vaag, gedupliceerd, verouderd of anders dan het zichtbare label is, wordt de interface moeilijker te gebruiken. Soms zelfs erger: aria-label kan betere tekst overschrijven die al in de DOM aanwezig was.
Het doel is niet om meer ARIA toe te voegen. Het doel is om de naam, rol, status en bedoeling van elk interface-element duidelijk te maken.
De toegankelijke naam, in gewone taal
De meeste interactieve elementen hebben een toegankelijke naam. Screenreaders gebruiken die naam om aan te kondigen wat het element is.
Bijvoorbeeld:
<button>Save changes</button>
Een screenreader kan iets aankondigen als: “Save changes, button.” De rol komt van het native button-element. De naam komt van de tekst erin.
Dat is de ideale situatie: zichtbare tekst en toegankelijke naam komen overeen.
ARIA-labelattributen worden nuttig wanneer de zichtbare interface geen volledige naam biedt, of wanneer de naam uit een ander element moet komen. De belangrijkste attributen zijn:
aria-label: geeft een string direct op het element.aria-labelledby: verwijst naar een of meer elementen waarvan de tekst de naam wordt.aria-describedby: verwijst naar ondersteunende beschrijvingstekst, niet naar de hoofdnaam.
Deze drie zijn verwant, maar niet onderling uitwisselbaar.
Eerste regel: geef de voorkeur aan native HTML en zichtbare labels
Als je zichtbare tekst op het bedieningselement kunt zetten, doe dat dan eerst.
Dit is beter:
<button>Delete invoice</button>
Dan dit:
<button aria-label="Delete invoice">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
Het tweede patroon is geldig voor een knop met alleen een icoon. Maar als het ontwerp zichtbare tekst kan verdragen, helpt zichtbare tekst iedereen: screenreadergebruikers, gebruikers van spraakherkenning, mensen met cognitieve belasting, mensen die snel scannen en mensen die vertaaltools gebruiken.
Dit is een terugkerend thema in toegankelijkheidswerk. Native HTML en zichtbare affordances lossen meer problemen op dan verborgen metadata. Hetzelfde principe geldt breder voor knopsemantiek; als je team UI-bedieningselementen auditt, is onze checklist voor toegankelijke webknoppen een goede aanvulling op deze gids.
Wanneer aria-label het juiste hulpmiddel is
Gebruik aria-label wanneer een element een toegankelijke naam nodig heeft en er geen geschikte zichtbare tekst is om naar te verwijzen.
Het klassieke geval is een knop met alleen een icoon:
<button aria-label="Search">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- icon -->
</svg>
</button>
Dit is redelijk. Het zichtbare icoon suggereert zoeken, maar het SVG-pad zelf biedt geen betrouwbare naam. aria-label levert die naam.
Andere goede gevallen zijn:
- Een sluitknop die alleen wordt weergegeven door een “X”.
- Een navigatielandmark die een specifiekere naam nodig heeft, zoals
aria-label="Product". - Een herhaald bedieningselement waarbij zichtbare context geen onderdeel is van de knoptekst.
Bijvoorbeeld:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
Beide zijn navigatielandmarks, maar hun labels helpen gebruikers ze te onderscheiden wanneer zij via landmarks navigeren.
Wanneer aria-label het verkeerde hulpmiddel is
Voeg niet zomaar aria-label toe omdat een test zegt dat een element een label nodig heeft. Herstel eerst de markup.
Slecht:
<div role="button" tabindex="0" aria-label="Submit">Submit</div>
Beter:
<button>Submit</button>
Het eerste voorbeeld creëert onnodig werk. Je moet nu toetsenbordgedrag, disabled-states, formuliergedrag en verwachtingen opnieuw maken die native knoppen al bieden.
Vermijd ook het gebruik van aria-label om zichtbare tekst een andere naam te geven op een manier die de betekenis verandert.
<button aria-label="Delete invoice">Remove</button>
Dit lijkt klein, maar het kan gebruikers verwarren die op spraakinvoer vertrouwen. Als een zichtbare knop “Remove” zegt, maar de toegankelijke naam “Delete invoice” is, krijgt een gebruiker die “click Remove” probeert te zeggen mogelijk niet het verwachte resultaat. De WCAG-eis “label in name” bestaat precies om deze reden: zichtbare tekst zou doorgaans in de toegankelijke naam moeten zijn opgenomen.
Een betere versie:
<button aria-label="Remove invoice">Remove</button>
Vaak nog beter:
<button>Remove invoice</button>
Grijp naar aria-labelledby wanneer zichtbare tekst al bestaat
Als de labeltekst al op de pagina staat, is aria-labelledby meestal beter dan aria-label.
Voorbeeld:
<h2 id="billing-title">Billing address</h2>
<section aria-labelledby="billing-title">
...
</section>
De toegankelijke naam van de sectie komt nu uit de zichtbare kop. Je voorkomt het dupliceren van strings, wat vertaalfouten en verouderde labels vermindert.
Dit is vooral nuttig voor formuliergroepen:
<fieldset aria-labelledby="shipping-speed-title">
<legend id="shipping-speed-title">Shipping speed</legend>
<label>
<input type="radio" name="shipping" value="standard">
Standard
</label>
<label>
<input type="radio" name="shipping" value="express">
Express
</label>
</fieldset>
In veel gevallen is de native legend genoeg zonder ARIA. Het punt is dat zichtbare labels leidend moeten zijn. ARIA moet bestaande betekenis verbinden, niet er een tweede privéversie van maken.
Gebruik aria-describedby voor hulptekst, niet voor de naam
Een beschrijving is geen label.
Bekijk dit veld:
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-help">
<p id="password-help">Use at least 12 characters.</p>
De toegankelijke naam is “Password.” De beschrijving is “Use at least 12 characters.” Een screenreader kan beide aankondigen, maar ze dienen verschillende doelen.
Doe dit niet:
<input type="password" aria-label="Use at least 12 characters">
Dat noemt het veld naar de instructie, niet naar het concept. Een gebruiker die door een formulier navigeert, wil eerst weten wat het veld is en daarna welke beperkingen gelden.
Dit onderscheid is ook belangrijk bij foutmeldingen:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
Het label blijft stabiel. De foutmelding wordt ondersteunende context.
Herhaalde bedieningselementen hebben unieke namen nodig
Lijsten en kaarten zijn plekken waar ARIA-labels vaak noodzakelijk worden.
Slecht:
<button>Delete</button>
<button>Delete</button>
<button>Delete</button>
Een screenreadergebruiker die via knoppen navigeert, kan drie keer “Delete, button” horen zonder context.
Goed:
<button aria-label="Delete report: Q4 revenue">Delete</button>
<button aria-label="Delete report: Hiring plan">Delete</button>
<button aria-label="Delete report: Vendor list">Delete</button>
Dit is een legitiem gebruik van aria-label: de zichtbare tekst blijft beknopt, terwijl de toegankelijke naam het object bevat.
Maar gebruik dit patroon zorgvuldig. Als de objectnaam zichtbaar in de buurt staat, kan aria-labelledby beter onderhoudbaar zijn:
<article>
<h3 id="report-q4">Q4 revenue</h3>
<button aria-labelledby="delete-q4 report-q4" id="delete-q4">Delete</button>
</article>
De toegankelijke naam wordt “Delete Q4 revenue.” Dit voorkomt dat je de rapporttitel in een attribuut dupliceert.
Label niet alles
Niet elk element heeft een ARIA-label nodig.
Statische tekst meestal niet. Decoratieve iconen niet. Containers niet, tenzij ze een betekenisvolle landmark- of widgetrol hebben. Te veel labelen kan een pagina rumoerig en moeilijker navigeerbaar maken.
Gebruik voor afbeeldingen het afbeeldingsspecifieke model: betekenisvolle afbeeldingen hebben nuttige alt nodig; decoratieve afbeeldingen hebben lege alt="" nodig. Gebruik ARIA-labels niet als vervanging voor goede afbeeldingstekst. Als je team die concepten door elkaar haalt, kijk dan opnieuw naar pragmatische alt-tekst voor afbeeldingen en scheid afbeeldingsalternatieven van namen van bedieningselementen.
Een veelgemaakte fout is elke SVG een aria-label geven. Als de SVG in een knop staat en de knop al een naam heeft, moet het icoon meestal verborgen worden voor ondersteunende technologie:
<button aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
Anders kan de gebruiker redundante of vreemde aankondigingen horen, afhankelijk van de combinatie van browser en ondersteunende technologie.
Controleer de berekende naam, niet alleen de code
Toegankelijkheidsbugs overleven code reviews vaak omdat de markup aannemelijk lijkt.
Moderne browserontwikkelaarstools kunnen de berekende accessibility tree tonen. Inspecteer in Chrome, Edge, Firefox en Safari het element en zoek naar toegankelijkheidsinformatie zoals rol, naam en beschrijving. Je controleert drie dingen:
- Is de rol wat je verwacht?
- Is de toegankelijke naam duidelijk en specifiek?
- Is de beschrijving behulpzaam zonder de naam te vervangen?
Test daarna een paar flows met een echte screenreader. Je hoeft geen fulltime expert in ondersteunende technologie te worden om de basisproblemen te vinden. Op macOS is VoiceOver ingebouwd. Op Windows wordt NVDA veel gebruikt en is het gratis. Test op mobiel waar relevant met VoiceOver op iOS en TalkBack op Android.
Geautomatiseerde tools zijn nuttig, maar ze kunnen niet betrouwbaar bepalen of “Open,” “Read more,” of “Delete” voldoende context heeft. Behandel automatisering als een vangnet, niet als een rechter. Dit lijkt op performance-auditing: een rapport kan je wijzen op verdachte plekken, maar je moet de impact nog steeds interpreteren. Dezelfde rustige aanpak die we aanbevelen voor een Lighthouse-rapport lezen zonder in paniek te raken geldt hier ook.
Een praktische reviewchecklist
Vraag vóór het shippen van ARIA-labels:
- Kan dit in plaats daarvan native HTML zijn?
- Is er zichtbare tekst die als label moet worden gebruikt?
- Als er zichtbare tekst is, bevat de toegankelijke naam die dan?
- Zijn herhaalde bedieningselementen uniek wanneer ze buiten visuele context worden genavigeerd?
- Is hulptekst verbonden met
aria-describedby, en niet in het label geforceerd? - Zijn decoratieve iconen verborgen voor ondersteunende technologie?
- Heeft iemand de berekende toegankelijke naam gecontroleerd in browserdevtools?
- Is er voor de kritieke flow minstens één echte screenreaderpass gedaan?
Deze checklist vangt de meeste labelproblemen voordat ze gebruikersproblemen worden.
De stille discipline van goede ARIA
Goed ARIA-werk is zelden dramatisch. Het is vooral terughoudendheid.
Gebruik echte knoppen. Gebruik echte labels. Houd zichtbare en toegankelijke namen op één lijn. Voeg aria-label alleen toe wanneer er geen betere zichtbare bron is. Gebruik aria-labelledby wanneer de pagina al de juiste tekst bevat. Gebruik aria-describedby voor ondersteunende instructies en fouten.
Het webplatform geeft ontwikkelaars veel gratis wanneer we het direct gebruiken. ARIA is er voor de gaten. De vaardigheid is weten wanneer er echt een gat is.