Toegankelijke formulieren: labels, foutmeldingen en validatie
- Johan
- 0
- Posted on
Toegankelijke formulieren implementeren (praktische handleiding)
Formulieren zijn de meest voorkomende bron van WCAG-fouten in websites en apps: ontbrekende of verkeerd gekoppelde labels, ontoegankelijke foutmeldingen, slechte focus-afhandeling en verkeerd gebruik van ARIA leiden tot onbruikbare formulieren voor mensen met een beperking. Ontwikkelaars en contentteams handhaven vaak visuele oplossingen zonder onderliggende semantiek of toegankelijke interactie.
Wij helpen praktijkgericht: concrete code-snippets, stap-voor-stap implementatie, testinstructies en edge-cases. Gebruik onze WCAG checker/validator om je formulier direct te scannen, download onze plugin voor CI-integratie en neem contact op via het contactformulier — we reageren binnen 24 uur.
Het probleem in de praktijk
Veelvoorkomende fouten
- Ontbrekende
<label>of niet-gekoppeldefor-attributen. - Foutmeldingen alleen visueel weergegeven (kleur/tekst), zonder ARIA of role zodat screenreaders ze niet melden.
- Geen focus naar foutveld bij submit, waardoor keyboard-only gebruikers vastlopen.
- Verwarrende volgorde in DOM vs visuele layout (tabvolgorde inconsistent).
- Misbruik van ARIA in plaats van native HTML-elementen.
Waarom dit grote impact heeft
Mensen die screenreaders, toetsenbord of spraakbesturing gebruiken, vertrouwen op semantiek, labels en live-regions. Zonder die informatie kan een gebruiker geen formulier invullen of fouten herstellen. Dit schaadt toegankelijkheid (WCAG 2.1: 1.3.1, 3.3.1, 2.1.1) en conversie.
Zo los je dit op in code
1. Gebruik altijd semantische HTML en gekoppelde labels
<form id="signup" novalidate>
<div class="form-row">
<label for="email">E-mailadres</label>
<input id="email" name="email" type="email" required aria-describedby="email-help email-error">
<div id="email-help">We sturen een bevestigingsmail</div>
<div id="email-error" class="error" aria-live="polite"></div>
</div>
</form>
Toelichting
- Koppel
<label for="id">aanidvan het input-element — dit is de meest betrouwbare methode (WCAG 2.1, 3.3.2). - Gebruik
aria-describedbyom aanvullende help- en foutteksten te koppelen. - Gebruik
aria-live="polite"ofrole="alert"voor dynamische foutmeldingen zodat screenreaders ze voorlezen.
2. Real-time validatie + foutsummary met focus management
<div id="error-summary" class="error-summary" role="alert" aria-labelledby="error-summary-title" tabindex="-1" hidden>
<h2 id="error-summary-title">Er zijn fouten in het formulier</h2>
<ul id="error-list"></ul>
</div>
function showErrors(errors){
const summary = document.getElementById('error-summary');
const list = document.getElementById('error-list');
list.innerHTML = '';
errors.forEach(err => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = '#'+err.field;
a.textContent = err.message;
a.addEventListener('click', e => {
e.preventDefault();
const field = document.getElementById(err.field);
field.focus();
});
li.appendChild(a);
list.appendChild(li);
// update inline message
const msg = document.getElementById(err.field+'-error');
msg.textContent = err.message;
msg.setAttribute('aria-live','assertive');
const field = document.getElementById(err.field);
field.setAttribute('aria-invalid','true');
});
summary.hidden = false;
summary.focus();
}
Toelichting
- Toon een error summary bovenaan met links naar de eerste foutvelden. Zet
tabindex="-1"en focus op de summary zodat screenreader- en toetsenbordgebruikers direct informatie hebben. - Zet
aria-invalid="true"op het geïdentificeerde inputveld en update het gekoppelde foutbericht (met id <veld>-error).
3. Vermijd onnodige ARIA en geef prioriteit aan native elementen
Zet geen role="textbox" op een <input>, gebruik geen aria-hidden voor content die visueel ook nodig is. ARIA is bedoeld als aanvulling wanneer native elementen niet volstaan.
4. CSS: zichtbare focus- en foutstijl
input:focus{outline:3px solid #005fcc; outline-offset:2px;}
.error{color:#a94442;}
input[aria-invalid="true"]{border-color:#a94442; box-shadow:0 0 0 3px rgba(169,68,66,0.15);}
5. Voor server-side gerenderde fouten
Zorg dat server-rendered foutmeldingen exact dezelfde structuur hebben: error summary met id, individuele fout-ID’s en aria-invalid op velden. Voeg inline JavaScript toe die bij pagina-lading focus naar error summary zet.
Server-side focus script (progressive enhancement)
document.addEventListener('DOMContentLoaded', function(){
var summary = document.getElementById('error-summary');
if(summary && !summary.hidden){ summary.focus(); }
});
Checklist voor developers
- Labels gekoppeld met
for+ uniekeid. - Inline hulptekst gekoppeld via
aria-describedby. - Fouten zichtbaar bovenaan (error summary) met
role="alert"entabindex="-1"en focus. - Inline foutberichten geüpdatet en voorzien van
aria-liveofrole. - Velden met fouten:
aria-invalid="true"en link in summary naar veld. - Toegankelijke keyboard-navigatie, correcte tabvolgorde (geen tabindex>0).
- Geen overbodige ARIA; prefer native controls.
- Contrast en zichtbare focus-states voldoen aan WCAG AA.
- Automated tests: run axe-core en onze WCAG checker/validator in CI.
Tips voor designers en redacties
Ontwerpprincipes
- Maak foutmeldingen duidelijk en beknopt (wat is fout, waarom en hoe te herstellen).
- Gebruik kleur nooit als enige indicatie — voeg iconen of tekst toe.
- Zorg dat helperteksten niet visueel verborgen zijn zonder alternatieve toegankelijkheid.
Content-editors: schrijf toegankelijke foutteksten
- Vermijd jargon; benoem veldnamen zoals op het formulier (“E-mailadres ontbreekt”).
- Geef concrete actie (“Vul een geldig e-mailadres in, bijvoorbeeld naam@voorbeeld.nl”).
- Beperk lengte; plaats uitgebreide hulp in een help-popup die ook toegankelijk is (focusable, ARIA-labels).
Hoe test je dit?
Handmatige tests (stap-voor-stap)
- Keyboard-only: navigeer vanaf de pagina-top naar het formulier en submit zonder waarden. Controleer dat de error summary focus krijgt en dat iedere foutlink de focus naar het veld brengt.
- Screenreader: gebruik NVDA (Windows) of VoiceOver (macOS). Herhaal de stap hierboven en luister of foutmeldingen voorgelezen worden bij verschijnen.
- Contrast en focus: zoom tot 200% en controleer zichtbaarheid van focus en foutstijlen.
- Mobile/Touch: controleer dat inline fouten en focus werken op mobiele schermen en dat je naar fouten kunt scrollen.
Automated tests en onze tools
Voer axe-core lokaal of in CI uit; bouw testcases voor het formulier. Gebruik onze WCAG checker/validator op wcagtool.nl/checker voor een eerste scan. Download onze browser-plugin om tijdens development live feedback te krijgen: wcagtool.nl/plugin. Integreer scans in CI: we bieden een CLI en API voor geautomatiseerde scans.
Specifieke testcases (copy-paste)
// Cypress voorbeeld: test error summary en focus
cy.visit('/signup');
cy.get('button[type="submit"]').click();
cy.get('#error-summary').should('be.visible').and('have.attr','tabindex','-1');
cy.get('#error-summary').focus();
cy.focused().should('have.attr','id','error-summary');
Praktische mini-how-to’s
Inline validatie bij blur
document.querySelectorAll('input[required]').forEach(input => {
input.addEventListener('blur', (e) => {
if(!e.target.checkValidity()){
const id = e.target.id + '-error';
document.getElementById(id).textContent = e.target.validationMessage;
e.target.setAttribute('aria-invalid','true');
} else {
e.target.removeAttribute('aria-invalid');
document.getElementById(e.target.id + '-error').textContent = '';
}
});
});
Formulier submit validatie: focus eerste fout
document.getElementById('signup').addEventListener('submit', function(e){
e.preventDefault();
const errors = [];
// eenvoudige validatie
const email = document.getElementById('email');
if(!email.value || !email.checkValidity()){
errors.push({field:'email', message:'Vul een geldig e-mailadres in.'});
}
if(errors.length){
showErrors(errors); // zie eerder showErrors functie
return false;
}
// verzenden via fetch...
});
Accessible datepicker: fallback naar native
Gebruik input type="date" waar mogelijk; voor custom pickers zorg voor volledige keyboardbediening, focusbeheer en ARIA-acties. Bied altijd een tekstinvoerveld met juiste formaat-hint.
Veelvoorkomende valkuilen en oplossingen
Val: foutmeldingen worden niet voorgelezen
Oplossing: zorg dat foutmelding een live-region is (aria-live of role="alert") of focus te geven op error summary. Test met screenreader.
Val: tabindex > 0 gebruikt om layout te fixen
Oplossing: pas DOM-structuur of CSS order aan, gebruik flexbox/grid en vermijd positieve tabindex-waarden die tabvolgorde door elkaar halen.
Val: icon als enige foutindicatie
Oplossing: voeg tekst en aria-labels toe. Voor beeldiconen: <span aria-hidden="true">⚠️</span> <span class="sr-only">Fout:</span>.
Extra testtools en integratie
Gebruik deze combinatie voor betrouwbare controles: a) onze WCAG checker/validator (https://wcagtool.nl/checker) voor snelle scans; b) browser plugin (https://wcagtool.nl/plugin) tijdens development; c) axe-core in CI; d) handmatige screenreader- en keyboardtests.
Voor vragen of implementatiehulp: stuur ons een bericht via het contactformulier. Wij garanderen antwoord binnen 24 uur en bieden optionele code review-sessies.
Direct testen: gebruik onze online tool om je formulier te scannen: wcagtool.nl/checker. Download de plugin voor snelle feedback tijdens development: wcagtool.nl/plugin.
Laatste praktische tip
Voeg dit kleine snippet toe aan elke pagina met formulieren zodat server-side fouten altijd focus krijgen bij reload:
(function(){var summary=document.getElementById('error-summary');if(summary && !summary.hidden){summary.setAttribute('tabindex','-1');summary.focus();}})();
Nu testen: draai direct een scan met onze WCAG checker/validator op wcagtool.nl/checker of download de plugin via wcagtool.nl/plugin. Vragen? Gebruik het contactformulier — we beantwoorden binnen 24 uur.