Een toegankelijk formulier maak je met zichtbare labels die in de code aan hun veld gekoppeld zijn, de juiste autocomplete-attributen, foutmeldingen in tekst bij het veld en een volgorde die met alleen een toetsenbord werkt. Voor een webshop geldt dat extra streng voor de checkout. Daar haakt een bezoeker die vastloopt direct af, en daar kijkt de European Accessibility Act specifiek naar.
Dit artikel hoort bij onze complete gids over website-toegankelijkheid. We lopen de succescriteria uit WCAG 2.2 langs die het vaakst misgaan in formulieren, met codevoorbeelden die je direct kunt overnemen. Elk criteriumnummer en niveau komt uit de officiële WCAG 2.2-specificatie.
Wil je eerst het grotere plaatje van WCAG 2.2 en de nieuwe criteria, lees dan WCAG 2.2 uitgelegd.
Waarom de European Accessibility Act e-commerce raakt
De European Accessibility Act noemt e-commercediensten uitdrukkelijk als dienst die toegankelijk moet zijn. In Richtlijn (EU) 2019/882 staan "e-commerce services" in artikel 2, lid 2, onder f. Artikel 3 omschrijft ze als diensten die op afstand via websites en mobiele diensten worden geleverd, op verzoek van een consument, met het oog op een consumentenovereenkomst. Lidstaten passen de regels toe vanaf 28 juni 2025.
Bijlage I, afdeling IV, onder g maakt het concreet voor webshops. Je geeft de beschikbare toegankelijkheidsinformatie over de producten die je verkoopt. En de functies voor identificatie, beveiliging en betaling moeten waarneembaar, bedienbaar, begrijpelijk en robuust zijn. Dat zijn precies je inlog-, account- en afrekenformulieren.
Een micro-onderneming die diensten levert, is volgens artikel 4, lid 5 vrijgesteld van deze eisen. Of de EAA voor jouw bedrijf geldt, lees je in European Accessibility Act. Dit artikel is uitleg, geen juridisch advies; raadpleeg bij twijfel een jurist.
Labels: elk veld een zichtbare, gekoppelde naam
Elk invoerveld heeft een zichtbaar label nodig dat in de code aan het veld gekoppeld is. Criterium 3.3.2 Labels or Instructions (niveau A) vraagt om labels of instructies waar invoer nodig is. Criterium 1.3.1 Info and Relationships (niveau A) vraagt dat de relatie tussen label en veld ook programmatisch vast te stellen is, zodat een screenreader het label voorleest als het veld focus krijgt.
De eenvoudigste manier is een label-element met een for-attribuut dat verwijst naar de id van het veld. Een klik op het label zet dan ook de cursor in het veld, wat helpt op kleine schermen.
<label for="email">E-mailadres</label>
<input type="email" id="email" name="email" autocomplete="email" required>
<!-- Niet doen: alleen een placeholder -->
<input type="email" placeholder="E-mailadres">
Een placeholder is geen label. Hij verdwijnt bij het typen, heeft vaak weinig contrast en is na het invullen niet meer te controleren. Gebruik een placeholder hooguit voor een voorbeeld, zoals "1234 AB".
Autocomplete: laat de browser het werk doen
Met autocomplete-attributen vertel je de browser welk soort gegevens een veld vraagt, zodat die het automatisch kan invullen. Criterium 1.3.5 Identify Input Purpose (niveau AA) vraagt dat het doel van velden voor gegevens over de gebruiker zelf programmatisch vast te stellen is. WCAG somt de geldige doelen op in een vaste lijst, waaronder naam, e-mail, telefoon, adres, postcode en betaalgegevens.
Voor mensen met een motorische of cognitieve beperking scheelt dit veel typwerk en fouten. Voor iedereen maakt het de checkout sneller.
<label for="naam">Volledige naam</label>
<input id="naam" name="naam" autocomplete="name">
<label for="straat">Straat en huisnummer</label>
<input id="straat" name="straat" autocomplete="street-address">
<label for="postcode">Postcode</label>
<input id="postcode" name="postcode" autocomplete="postal-code">
<label for="plaats">Plaats</label>
<input id="plaats" name="plaats" autocomplete="address-level2">
<label for="tel">Telefoonnummer (optioneel)</label>
<input type="tel" id="tel" name="tel" autocomplete="tel">
Verplichte velden en groeperen met fieldset
Verplichte velden markeer je zowel zichtbaar als in de code, en velden die bij elkaar horen groepeer je met fieldset en legend. Het required-attribuut zorgt dat een screenreader "verplicht" voorleest. Gebruik je een sterretje, leg dan bovenaan uit wat het betekent. Zijn bijna alle velden verplicht, markeer dan liever de paar optionele velden.
Een fieldset met legend valt onder criterium 1.3.1. Het is vooral nodig bij keuzerondjes en selectievakjes, waar het label van één optie zonder de vraag geen betekenis heeft. "Afhalen" zegt weinig; "Bezorgmethode: afhalen" wel.
<fieldset>
<legend>Bezorgmethode</legend>
<input type="radio" id="bezorg-thuis" name="bezorging" value="thuis" required>
<label for="bezorg-thuis">Thuisbezorging</label>
<input type="radio" id="bezorg-afhaal" name="bezorging" value="afhaalpunt">
<label for="bezorg-afhaal">Afhaalpunt</label>
</fieldset>
Gebruik fieldset ook om het factuuradres en het bezorgadres van elkaar te scheiden. Zonder groep hoort een screenreadergebruiker twee keer "Postcode" zonder te weten bij welk adres.
Foutmeldingen en foutsuggesties
Een foutmelding moet in tekst zeggen welk veld fout is en wat er mis is. Criterium 3.3.1 Error Identification (niveau A) vraagt dat een automatisch gevonden invoerfout wordt aangewezen en in tekst beschreven. Alleen een rode rand is dus niet genoeg. Criterium 3.3.3 Error Suggestion (niveau AA) gaat verder: als je weet hoe de fout op te lossen is, geef je die suggestie, tenzij dat de beveiliging of het doel ondermijnt.
"Ongeldige invoer" voldoet niet aan 3.3.3. "Vul een postcode in zoals 1234 AB" wel. Koppel de melding aan het veld met aria-describedby en markeer het veld met aria-invalid, zodat een screenreader de fout voorleest als het veld focus krijgt.
<label for="postcode">Postcode</label>
<input id="postcode" name="postcode" autocomplete="postal-code"
aria-invalid="true" aria-describedby="postcode-fout">
<p id="postcode-fout">Vul een Nederlandse postcode in, bijvoorbeeld 1234 AB.</p>
Bij een lang formulier helpt een samenvatting van alle fouten bovenaan, met links naar de velden. Zet na het versturen de focus op die samenvatting. Gebruik ARIA zoals aria-invalid alleen waar het iets toevoegt; WAI-ARIA vult HTML aan, maar vervangt geen goede basis.
Voor de laatste stap van een bestelling geldt nog criterium 3.3.4 Error Prevention (niveau AA). Bij inzendingen met financiële of juridische gevolgen moet de gebruiker de invoer kunnen controleren en corrigeren, kunnen terugdraaien of expliciet bevestigen. Een overzichtspagina vóór "Bestelling plaatsen" voldoet daar meestal aan.
Focusvolgorde, toetsenbord en doelgrootte
Een formulier moet volledig met een toetsenbord te bedienen zijn, in een logische volgorde, met zichtbare focus. Criterium 2.1.1 Keyboard (niveau A) vraagt dat alle functies met een toetsenbord werken. Criterium 2.4.3 Focus Order (niveau A) vraagt een volgorde die betekenis en bediening behoudt. Criterium 2.4.7 Focus Visible (niveau AA) vraagt een zichtbare focusindicator.
Veelvoorkomende fouten in een checkout:
- Een eigen keuzelijst of datumkiezer die alleen op een muisklik reageert.
- Een
tabindexmet een positieve waarde, waardoor de focus door het formulier springt. - Een focusrand die met CSS is weggehaald (
outline: none) zonder vervanging. - Een vaste balk onderaan die het gefocuste veld afdekt. WCAG 2.2 voegde daarvoor criterium 2.4.11 Focus Not Obscured (Minimum, niveau AA) toe.
Voor aanraakschermen en mensen met trillende handen telt de grootte van knoppen en vakjes. Criterium 2.5.8 Target Size (Minimum, niveau AA) vraagt een doelgebied van minstens 24 bij 24 CSS-pixels. Er zijn uitzonderingen, onder meer als er genoeg ruimte omheen zit, als er een gelijkwaardig groter element is of bij links in lopende tekst. Kleine selectievakjes voor de algemene voorwaarden en minuscule plus- en minknoppen in de winkelwagen zijn de bekende probleemgevallen.
Overbodige invoer en tijdslimieten
Vraag nooit twee keer om dezelfde gegevens in hetzelfde proces. Criterium 3.3.7 Redundant Entry (niveau A), nieuw in WCAG 2.2, vraagt dat eerder ingevulde informatie automatisch is ingevuld of te selecteren is. Uitzonderingen zijn als herhalen essentieel is, nodig is voor beveiliging of als de eerdere gegevens niet meer geldig zijn.
Het bekendste voorbeeld in een webshop is het factuuradres. Een selectievakje "Factuuradres is gelijk aan bezorgadres" voldoet. Een tweede, leeg adresformulier niet. Een wachtwoord twee keer laten intypen valt onder de beveiligingsuitzondering.
Tijdslimieten vallen onder criterium 2.2.1 Timing Adjustable (niveau A). Heeft je checkout of winkelwagen een limiet, dan moet de gebruiker die kunnen uitzetten, kunnen aanpassen tot minstens tien keer de standaardduur, of vooraf gewaarschuwd worden en minstens 20 seconden krijgen om met een simpele handeling te verlengen. Uitzonderingen zijn realtime-gebeurtenissen zoals een veiling, limieten die essentieel zijn en limieten langer dan 20 uur. Een sessie die na tien minuten stil verloopt en de winkelwagen leegt, is dus een probleem.
Inloggen zonder puzzels
Inloggen of je identiteit bevestigen mag geen cognitieve test vereisen, zoals een wachtwoord onthouden of een code overtypen, tenzij er een alternatief of hulpmiddel is. Dat vraagt criterium 3.3.8 Accessible Authentication (Minimum, niveau AA), nieuw in WCAG 2.2. Uitzonderingen op AA zijn het herkennen van objecten en het herkennen van eigen content, zoals een foto die je zelf hebt geüpload.
De Understanding-pagina bij 3.3.8 maakt een paar dingen concreet:
- Plakken moet werken. Blokkeer je plakken in het wachtwoordveld, of verhinder je een wachtwoordmanager om het veld te vullen, dan faal je op dit criterium, tenzij er een andere methode is.
- Verificatiecodes overtypen is niet genoeg. Een dienst die alleen handmatig overtypen van een code toestaat, voldoet niet. De gebruiker moet de code minstens kunnen plakken.
- CAPTCHA's hebben een niet-cognitief alternatief nodig, tenzij het gaat om objectherkenning. Een audio-CAPTCHA die je moet uitschrijven, telt niet als alternatief.
Praktische alternatieven voor een CAPTCHA zijn een onzichtbare controle op de achtergrond, een verborgen honeypot-veld, inloggen via een link per e-mail of een passkey. Zet op wachtwoordvelden autocomplete="current-password" of autocomplete="new-password", zodat wachtwoordmanagers ze herkennen. Op niveau AAA (criterium 3.3.9) vervalt ook de uitzondering voor objectherkenning.
De betaalstap en iframes van betaalproviders
De betaalstap is vaak het lastigste deel om toegankelijk te krijgen, omdat een deel ervan niet in je eigen code zit. Veel webshops tonen de kaartvelden in een iframe van de betaalprovider of sturen de klant door naar een betaalpagina van die provider. Wat daarin gebeurt, kun je zelf meestal niet aanpassen.
Toch blijft het onderdeel van jouw bestelproces, en de EAA noemt de betaalfunctie van een e-commercedienst uitdrukkelijk. Hoe de verantwoordelijkheid precies verdeeld is tussen jou en je provider, verschilt per situatie en vraagt bij twijfel juridisch advies. Wat je in elk geval kunt doen:
- Vraag je betaalprovider naar zijn toegankelijkheidsinformatie of -verklaring, en naar de WCAG-versie en het niveau waaraan de betaalcomponenten getest zijn.
- Test de betaalstap zelf met alleen een toetsenbord en met een screenreader, inclusief een foutieve invoer en een 3D Secure-controle.
- Geef een iframe een titel die zegt wat erin zit, bijvoorbeeld
title="Betaalgegevens", als je die zelf instelt. - Bied meerdere betaalmethoden aan, zodat een klant die vastloopt in de ene methode een andere kan kiezen.
- Noem bekende problemen in je toegankelijkheidsverklaring, met een alternatieve manier om te bestellen.
Zo controleer je dit op je eigen site
- Loop je volledige bestelproces door met alleen een toetsenbord, van productpagina tot bevestiging. Noteer elke plek waar de focus verdwijnt of vastloopt.
- Controleer elk veld op een zichtbaar, gekoppeld label en de juiste autocomplete-waarde. In DevTools zie je in het toegankelijkheidspaneel welke naam een veld krijgt.
- Verstuur het formulier met opzet fout. Krijg je per veld een foutmelding in tekst met een suggestie, en leest een screenreader die voor?
- Test inloggen met een wachtwoordmanager en kijk of plakken werkt in wachtwoord- en codevelden.
- Meet de doelgrootte van selectievakjes, keuzerondjes en knoppen in de winkelwagen op een telefoon.
- Draai een automatische scan op elke stap van de checkout. Die vindt ontbrekende labels en foutieve ARIA; de rest van deze lijst blijft handwerk. Meer over die combinatie lees je in website-toegankelijkheid testen.
De toegankelijkheidscontrole van Flowproof zit in de betaalde abonnementen Pro en Business en toetst je pagina's met axe-core aan WCAG 2.2 A en AA. Je kunt gratis starten en de abonnementen vergelijken op de prijzenpagina.