Formulieren op een website spelen een belangrijke rol: ze zorgen dat je kunt inloggen, bestellen, contact opnemen of solliciteren. Maar voor veel mensen zijn formulieren nog een frustrerende ervaring. Labels ontbreken, foutmeldingen zijn onduidelijk en het is niet altijd duidelijk wat je moet invullen.
Dit artikel laat je zien hoe het anders kan.
Duidelijke en beschrijvende labels
Wat maakt een label beschrijvend?
Elk invoerveld heeft een beschrijvend en zichtbaar label nodig. Gebruikers moeten weten wat ze moeten invullen voordat ze beginnen. De gebruiker moet in één oogopslag begrijpen wat er wordt verwacht. Een label zoals “Veld 1” of “Invoer” is te vaag. “E-mailadres” of “Achternaam” is wél beschrijvend.
Een kort label is prima, zolang het maar duidelijk is. “Datum” is bijvoorbeeld voldoende als er maar 1 invoerveld is. Splits je de invoer op in meerdere onderdelen (zoals een datum in dag, maand en jaar)? Geef elk onderdeel dan een eigen zichtbaar label.
Labels koppelen aan het bijbehorende veld
Gebruik een <label>-element voor het label. Koppel elk label aan een invoerveld met het for-attribuut.
<label for="naam">
Naam:
</label>
<input type="text" id="naam" name="naam">
Een label moet zichtbaar zijn voor alle gebruikers. Alleen een placeholdertekst is daarom niet genoeg, omdat die:
- verdwijnt als je begint met typen
- vaak (standaard) te weinig contrast heeft
- soms wordt verward met al ingevulde data
Let op: Een verborgen label via aria-label of een sr-only-class geeft wel een toegankelijke naam aan het invoerveld, maar is niet zichtbaar. Een schermlezer kondigt dit verborgen label wél aan, maar mensen die de pagina bekijken missen de context.
Laat het zichtbare label en de toegankelijke naam overeenkomen
Zorg dat het zichtbare label altijd terugkomt in de toegankelijke naam van het veld. Mensen die spraakbesturing gebruiken, bedienen invoervelden door het zichtbare label uit te spreken. Wijkt de toegankelijke naam af van wat er op het scherm staat? Dan werkt dat niet.
Waar plaats je een label?
Plaats het label op een voorspelbare plek. Bij tekstvelden en keuzelijsten zet je het label links van of boven het veld. Bij selectievakjes en keuzerondjes zet je het label rechts van het veld.
Met een label vergroot je ook direct het klikbare gebied van het invoerveld.
Markeer verplichte velden
Maak duidelijk welke velden verplicht zijn. Geef dit zichtbaar aan met tekst, een sterretje (asterisk) of een ander symbool. Als je een sterretje of symbool gebruikt, leg dan bovenaan het formulier uit wat het betekent. Zo weet iedereen direct welke velden verplicht zijn.
<label for="email">
E-mailadres (verplicht)
</label>
<input type="email" id="email" name="email" required>
Gebruik daarnaast het required-attribuut. Dit helpt schermlezers om aan te geven dat een veld verplicht is.
Geef instructies vooraf
Vertel vooraf wat je van de invoer verwacht, niet (alleen) achteraf als het mis gaat. Plaats de instructie in het label of koppel deze aan het invoerveld met het aria-describedby-attribuut.
Bij een geboortedatum kun je het verwachte formaat tonen:
<label for="geboortedatum">
Geboortedatum:
</label>
<span id="datum-hint">
Gebruik het formaat DD-MM-JJJJ
</span>
<input type="text" id="geboortedatum" name="geboortedatum" aria-describedby="datum-hint">
Geef bij velden waarbij in een specifiek formaat moet worden ingevuld altijd een voorbeeld. Denk dan aan: “Bijvoorbeeld 15-03-1990” bij een datumveld, of “Bijvoorbeeld 1234 AB” bij een postcodeveld.
Groepeer gerelateerde velden
Gebruik het <fieldset>-element met <legend> om gerelateerde invoervelden te groeperen. Dit is vooral belangrijk bij keuzerondjes en selectievakjes.
<fieldset>
<legend>
Kies je pakket:
</legend>
<input type="radio" id="basis" name="pakket" value="basis">
<label for="basis">
Basis
</label>
<input type="radio" id="premium" name="pakket" value="premium">
<label for="premium">
Premium
</label>
</fieldset>
De <legend> moet beschrijven waar de groep over gaat. Een schermlezer leest dit voor bij elk veld in de groep, zodat gebruikers de context behouden.
Help browsers met automatisch invullen
Browsers kunnen formulieren automatisch invullen als ze weten wat voor informatie je vraagt. Dit helpt niet alleen mensen met een cognitieve beperking, maar ook iedereen die snel een formulier wil invullen.
Gebruik het autocomplete-attribuut om aan te geven wat voor informatie je verwacht:
<label for="naam">
Naam:
</label>
<input type="text" id="naam" name="naam" autocomplete="name">
<label for="email">
E-mailadres:
</label>
<input type="email" id="email" name="email" autocomplete="email">
<label for="tel">
Telefoonnummer:
</label>
<input type="tel" id="tel" name="telefoon" autocomplete="tel">
Veelgebruikte inputdoelen
name: Volledige naamgiven-name: Voornaamfamily-name: Achternaamaddress-line1: Straatnaam + huisnummerpostal-code: Postcodeaddress-level2: Woonplaatsbday: Geboortedatumemail: E-mailadrestel: Telefoonnummer
Gebruik autocomplete bij alle velden die persoonlijke informatie van de gebruiker verzamelen. Vraag je om het informatie van iemand anders? Dan hoef je geen autocomplete te gebruiken.
Fouten afhandelen
Als er iets fout gaat, moet de gebruiker weten wáár de fout zit en wát er precies mis is. Beschrijf de fout altijd in tekst. Gebruik nooit alleen kleur, een icoon of een andere visuele aanwijzing om een fout aan te geven.
Foutmeldingen moeten zichtbaar blijven totdat de gebruiker de fout herstelt. Verwijder een melding niet automatisch na een paar seconden.
Vermijd ingebouwde browservalidatie
Browsers hebben ingebouwde validatie. Vermijd deze HTML-formuliervalidatie omdat deze meldingen vaak te vaag zijn (“Vul dit veld in”) en ze niet altijd goed worden aangekondigd door een schermlezer.
Schrijf daarom je eigen foutmeldingen. Zo heb je controle over de tekst en zorg je dat de melding toegankelijk is.
Identificeer en beschrijf fouten in tekst
Gebruik drie onderdelen om fouten duidelijk te maken:
- Een zichtbare foutmelding in tekst
- Koppel de foutmelding aan het veld met
aria-describedby - Markeer het veld als ongeldig met
aria-invalid="true"
<label for="naam">
Naam:
</label>
<input type="text" id="naam" name="naam" aria-invalid="true" aria-describedby="naam-fout">
<span id="naam-fout">
Naam is niet ingevuld. Vul je naam in.
</span>
Zet foutmeldingen dicht bij het betreffende veld. Gebruik nooit alleen kleur om fouten aan te geven.
Wees specifiek in foutmeldingen
Schrijf niet “Dit veld is verplicht”, maar zorg dat de gebruiker begrijpt om welk veld het gaat. Benoem daarbij het label van het element.
<label for="straat">
Straatnaam:
</label>
<input type="text" id="straat" name="straat" aria-invalid="true" aria-describedby="straat-fout">
<span id="straat-fout">
‘Straatnaam’ is niet ingevuld. Het is een verplicht veld. Vul je straatnaam in.
</span>
Maak een samenvatting bij meerdere fouten
Help gebruikers door alle fouten bovenaan te tonen. Maak van de foutmeldingen links naar de bijbehorende velden.
<div role="alert">
<h2>
Er zijn fouten in het formulier
</h2>
<ol>
<li>
<a href="#naam">
Naam is niet ingevuld. Vul je naam in.
</a>
</li>
<li>
<a href="#email">
E-mailadres ‘voorbeeld@’ is ongeldig. Gebruik het formaat voorbeeld@domein.nl.
</a>
</li>
</ol>
</div>
Als het formulier opnieuw geladen wordt na verzenden, pas dan ook het <title>-element aan. Vermeld daarin dat er fouten zijn, bijvoorbeeld: <title>Fouten gevonden – Contactformulier – Mijn website</title>. Schermlezergebruikers horen de paginatitel als eerste en weten zo direct dat ze actie moeten ondernemen.
Kondig foutmeldingen aan voor schermlezers
Verschijnen foutmeldingen dynamisch op de pagina, zonder dat de pagina opnieuw laadt? Dan moeten schermlezers die meldingen automatisch aankondigen.
Het role-attribuut met de waarde "alert" zorgt daarvoor. Gebruik role="alert" op de foutsammenvatting die verschijnt na het versturen van het formulier.
Foutmeldingen in fieldsets
Bij gegroepeerde velden (zoals keuzerondjes) plaats je de foutmelding direct na de <legend>. Koppel de foutelding aan elk individueel veld met aria-describedby.
<fieldset>
<legend>
Kies je betaalmethode (verplicht)
</legend>
<span id="betaling-fout">
Je hebt nog geen betaalmethode gekozen.
</span>
<input type="radio" id="ideal" name="betaling" value="ideal" aria-invalid="true" aria-describedby="betaling-fout">
<label for="ideal">
iDEAL
</label>
<input type="radio" id="creditcard" name="betaling" value="creditcard" aria-invalid="true" aria-describedby="betaling-fout">
<label for="creditcard">
Creditcard
</label>
</fieldset>
Suggesties voor correctie
Het identificeren van een fout is de eerste stap. De volgende stap is de gebruiker helpen om de fout op te lossen. Als het systeem kan bepalen wat een geldige correctie is, geef dan een suggestie voor verbetering van de invoer.
Er is een belangrijk verschil tussen foutidentificatie en foutsuggestie. Een melding als “E-mailadres is ongeldig” geeft wel aan waar de fout is de fout, maar helpt de gebruiker niet verder. Een melding zoals “Het e-mailadres is niet geldig. Controleer of je een @ hebt gebruikt, bijvoorbeeld naam@voorbeeld.nl.” geeft ook een suggestie voor verbetering.
Een suggestie voor verbetering van de invoer kan op verschillende manieren:
- Als er een verplicht invoerformaat vereist is:
- Bij een ongeldig e-mailadres: Het e-mailadres is niet geldig. Controleer of je een @ hebt gebruikt, bijvoorbeeld naam@voorbeeld.nl.
- Bij een verkeerd datumformaat: Vul je geboortedatum in als DD-MM-JJJJ, bijvoorbeeld 15-03-1990
- Bij een verkeerd postcodeformaat: Een postcode bestaat uit 4 cijfers en 2 letters, bijvoorbeeld 1234 AB
- Bij een te lang telefoonnummer: Een telefoonnummer bestaat uit maximaal 10 cijfers. Laat de landcode weg, bijvoorbeeld 0612345678.
- Als invoer binnen een (vooraf bepaald) bereik moet vallen: Voer een aantal tussen 1 en 50 in.
- Als het systeem een mogelijke correctie kan voorstellen op basis van bekende waarden: Bedoelde je ‘Amsterdam’?
Wanneer géén suggesties geven?
Geef geen suggesties als dit de beveiliging of het doel van de content in gevaar brengt. Bij een verkeerd wachtwoord vertel je niet wat er precies fout is. Bij een toets of examen geef je geen hints over het juiste antwoord.
Suggesties alleen verplicht als het systeem kan bepalen wat een geldige verbetering is. Bij een veld zoals “opmerking” is dat meestal niet mogelijk.
Voorkom onomkeerbare fouten
Sommige formulieren hebben grote gevolgen. Denk aan een bestelling plaatsen, een contract ondertekenen, of persoonlijke gegevens verwijderen. Gaat er dan iets mis, dan kun je dat niet zomaar terugdraaien.
Bied daarom minstens één van deze drie opties:
- Maak de actie omkeerbaar. Laat de gebruiker een bestelling annuleren of een wijziging ongedaan maken.
- Controleer de invoer vooraf. Check op fouten en geef de gebruiker de kans om ze te corrigeren vóórdat de actie wordt uitgevoerd.
- Laat de gebruiker bevestigen. Toon een overzichtspagina waar de gebruiker alles kan nakijken voordat het formulier definitief wordt verzonden.
Dit geldt voor formulieren met financiële transacties, wettelijke verplichtingen, het wijzigen of verwijderen van gegevens, en het verzenden van toets- of examenantwoorden.
Om te onthouden
Toegankelijke formulieren beginnen met de basis: duidelijke labels, heldere instructies en goede foutafhandeling. Met de juiste HTML-attributen help je niet alleen mensen met een beperking, maar maak je formulieren voor iedereen makkelijker te gebruiken.
Begin klein: Controleer eerst of alle velden zichtbare labels hebben. Voeg dan autocomplete toe. Verbeter je foutmeldingen. Stap voor stap maak je je formulieren toegankelijker.
Gerelateerde succescriteria
Dit artikel behandelt acht WCAG-succescriteria:
- 1.3.5 Identificeer het doel van de input (niveau AA)
- 2.4.6 Koppen en labels (niveau AA)
- 2.5.3 Label in naam (niveau A)
- 3.3.1 Foutidentificatie (niveau A)
- 3.3.2 Labels of instructies (niveau A)
- 3.3.3 Foutsuggestie (niveau AA)
- 3.3.4 Foutpreventie (wettelijk, financieel, gegevens) (niveau AA)
- 4.1.3 Statusberichten (niveau AA)