Formulieren zijn de plek waar je website ophoudt met praten en begint met luisteren: contactverzoeken, bestellingen, registraties, zoekopdrachten. Het is ook de plek waar toegankelijkheid het vaakst faalt. Het WebAIM Million-onderzoek, dat elk jaar de miljoen meestbezochte homepages scant, vindt consequent ontbrekende labels bij formuliervelden op bijna de helft daarvan, waarmee het een van de meest voorkomende toegankelijkheidsfouten op het web is. Het frustrerende eraan: toegankelijke formulieren zijn niet moeilijk. Een handvol HTML-attributen, correct gebruikt, bepaalt of een blinde gebruiker je een bericht kan sturen of stilletjes opgeeft, en of je formulier voldoet aan WCAG, wat de European Accessibility Act voor veel bedrijven tot wettelijke plicht heeft gemaakt. Deze gids loopt de vijf dingen langs die ertoe doen, met markup om te kopiëren, en sluit af met een eerlijke blik op WordPress-formulierplugins.
Waarom zijn formulieren het grootste toegankelijkheidsprobleem?
Een ziende muisgebruiker leest een formulier als een visueel geheel: de tekst naast een vakje hoort er duidelijk bij, de rode rand betekent duidelijk een fout. Hulptechnologie heeft niets van die context. Iemand met een schermlezer tabt van element naar element en hoort alleen wat de markup expliciet aan elk veld koppelt. Ontbreekt die koppeling, dan hoort de gebruiker bewerkbaar tekstveld, leeg, en moet hij raden wat het veld wil. Gebruikers van spraakbesturing lopen tegen hetzelfde probleem aan: klik e-mail zeggen werkt alleen als het veld programmatisch e-mail heet.
Dat is het kernprincipe achter elke regel in deze gids: elke visuele relatie in een formulier moet ook in de markup bestaan. Label bij veld, hint bij veld, fout bij veld, groep bij opties. De relevante WCAG-succescriteria (1.3.1 Info and Relationships, 3.3.1 Error Identification, 3.3.2 Labels or Instructions) komen allemaal terug op dat ene idee.
Formuliervelden correct labelen
De basis van elk toegankelijk formulier is het label-element, gekoppeld aan zijn veld met het attribuut for dat naar de id van het veld wijst:
<label for="email">E-mailadres</label>
<input type="email" id="email" name="email" autocomplete="email">
<!-- Extra hint, gekoppeld via aria-describedby -->
<label for="password">Wachtwoord</label>
<input type="password" id="password" name="password" aria-describedby="password-hint">
<p id="password-hint">Minimaal twaalf tekens.</p>Dat levert je drie dingen tegelijk op: schermlezers kondigen het label aan zodra het veld focus krijgt, op het label klikken zet de focus in het veld (een groter aanraakdoel op mobiel, voor iedereen), en spraakbesturing kan het veld bij naam aanspreken. Hints en formaatinstructies horen in een apart element waarnaar aria-describedby verwijst, zodat ze na het label worden aangekondigd zonder dat label vol te stoppen. Het attribuut autocomplete is een stille bonus: voor velden die persoonsgegevens verzamelen vraagt WCAG 1.3.5 erom, en het laat browsers het veld correct invullen, wat vooral gebruikers met motorische en cognitieve beperkingen helpt. De formuliertutorial van W3C behandelt elke variant van deze patronen.
Waarom een placeholder geen label is
Het formulierveld met alleen een placeholder is de meest gemaakte fout op het web die er toegankelijk uitziet. Het oogt strak, en het faalt op vier manieren tegelijk:
- De tekst verdwijnt bij invoer. De beschrijving lost precies op wanneer de gebruiker met het veld bezig is. Iedereen die ooit is vergeten wat een half ingevuld veld vroeg, kent dat gevoel.
- Het standaardgrijs faalt op contrast. Typische placeholderopmaak haalt de contrastverhouding van 4,5:1 niet die WCAG voor tekst vereist.
- De ondersteuning door hulptechnologie is wisselvallig. Sommige combinaties van schermlezer en browser kondigen placeholders aan, andere niet. Een label wordt door allemaal aangekondigd.
- Ingevulde velden lijken leeg, lege velden lijken ingevuld. Wie scant welke velden nog open staan, ziet het precies andersom.
Placeholders zijn prima als aanvulling, bijvoorbeeld een formaatvoorbeeld als naam@example.com in een netjes gelabeld veld. Als enige beschrijving van een veld zijn ze een WCAG 3.3.2-fout met goede typografie.
Verplichte velden toegankelijk markeren
Twee kanalen, altijd samen. Het machinekanaal is het HTML-attribuut required, waardoor browsers en schermlezers het veld als verplicht aankondigen en de ingebouwde validatie aanslaat. Het menselijke kanaal is zichtbare tekst: het woord verplicht (of het tegenovergestelde, optioneel) in het label. Het populaire rode sterretje alleen faalt op beide punten: kleur alleen mag geen informatie dragen (WCAG 1.4.1), en gebruik je het sterretje toch, dan moet de conventie minstens boven het formulier worden uitgelegd en in het label staan zodat hij wordt aangekondigd.
<label for="name">Naam (verplicht)</label>
<input type="text" id="name" name="name" required>Een pragmatische omkering levert vaak de schoonste formulieren op: is vrijwel elk veld verplicht, markeer dan alleen de optionele en zeg dat boven het formulier. En het beste verplichte veld is het veld dat je schrapt; elk veld dat een formulier niet vraagt, kan ook niet verkeerd worden ingevuld.
Foutmeldingen toegankelijk maken
Foutafhandeling is de plek waar formulieren de gebruikers verliezen die ze nog niet kwijt waren. WCAG 3.3.1 vereist dat fouten in tekst worden benoemd en aan de gebruiker beschreven. Het robuuste patroon per veld:
<label for="email">E-mailadres (verplicht)</label>
<input type="email" id="email" name="email" required
aria-invalid="true" aria-describedby="email-error">
<p id="email-error" class="error">
Vul een e-mailadres in, bijvoorbeeld naam@example.com.
</p>De onderdelen: aria-invalid="true" markeert het veld als foutief zodat schermlezers bij focus ongeldige invoer aankondigen, de melding is echte tekst (niet alleen een rode rand, niet alleen een icoon) en is met aria-describedby aan het veld gekoppeld, en de formulering zegt hoe je het probleem oplost, niet alleen dat er een is. Fout, corrigeer dit helpt niemand; Vul een datum in het formaat DD-MM-JJJJ in wel.
Voor validatie die bij het versturen draait, is er nog een stap die telt: verplaats na een mislukte verzending de toetsenbordfocus naar het eerste foutieve veld, of render bovenaan een foutoverzicht met role="alert" en links naar de betreffende velden. Iemand met een schermlezer die verstuurt en niets hoort, gaat ervan uit dat het formulier werkte. Stilte na een mislukte verzending is de wreedste formulierbug die er is.
Fieldset en legend: radiobuttons en checkboxes groeperen
Groepen radiobuttons en checkboxes hebben een structuur van twee niveaus: de groep heeft een vraag, elke optie heeft een label. Beide niveaus moeten in de markup staan, en de eigen elementen voor het groepsniveau zijn fieldset en legend:
<fieldset>
<legend>Voorkeur voor contact (verplicht)</legend>
<input type="radio" id="contact-email" name="contact" value="email">
<label for="contact-email">E-mail</label>
<input type="radio" id="contact-phone" name="contact" value="phone">
<label for="contact-phone">Telefoon</label>
</fieldset>Zonder de fieldset hoort iemand met een schermlezer die de groep in tabt alleen E-mail, radioknop, één van twee, en heeft hij geen idee op welke vraag de opties antwoord geven. Mét fieldset wordt de legend als eerste aangekondigd. Dezelfde structuur bedient groepen checkboxes en is het waard om te behouden, ook als een designsysteem de elementen tot onherkenbaar wordens toe restylet; de semantiek kost niets en draagt alles.
Zijn WordPress-formulierplugins toegankelijk?
Meestal kunnen ze het zijn, en geen enkele garandeert het. Het eerlijke beeld per plugin: Contact Form 7 rendert wat jij in de formuliertemplate schrijft, dus labels, fieldsets en de bedrading van foutmeldingen liggen volledig in jouw handen; de flexibiliteit die hem populair maakt, maakt het ook makkelijk om formulieren zonder labels uit te rollen. Gravity Forms heeft zijn markup een paar jaar geleden herzien met toegankelijkheid als expliciet doel en levert in actuele versies degelijke uitvoer. WPForms heeft eveneens in toegankelijke standaardinstellingen geïnvesteerd. In alle gevallen kunnen drie dingen een toegankelijke plugin alsnog breken: de opmaak van je thema (focusranden weggehaald, contrast verwoest), CAPTCHA's (een volledig ontoegankelijke drempel; honeypot-aanpakken omzeilen het probleem) en eigen veldtypes die er bovenop komen.
Test dus het gerenderde resultaat, niet de marketingpagina. De versie van twee minuten: trek je muis eruit en vul het formulier alleen met het toetsenbord in, waarbij je bij elke stap controleert of je de focus ziet, en verstuur het daarna leeg om te kijken of de foutmeldingen worden aangekondigd en bereikbaar zijn. Geautomatiseerde checkers als WAVE vangen de structurele helft, inclusief ontbrekende labels, in seconden.
Zo helpt InspectWP je formulierproblemen te vinden
Het rapport van InspectWP onderzoekt je gerenderde WordPress-site zoals een browser hem ziet, en meerdere controles raken formulieren rechtstreeks. Het markeert formulieren waarvan de action naar een onveilig HTTP-adres verstuurt, een probleem dat browsers met waarschuwingen afstraffen op precies het moment dat een bezoeker je gegevens wil toevertrouwen. Daarnaast dekt het rapport de toegankelijkheidsbasis rond je formulieren: afbeeldingen zonder alt-attribuut, de koppenhiërarchie waarop gebruikers van een schermlezer navigeren, en consolefouten die vaak kapotte validatiescripts verraden. Een gratis rapport is een snelle eerste scan over de pagina waarop je formulier staat.