Toegankelijke formulieren en focusbeheer: praktische implementatie
Formulieren en focusbeheer falen in de praktijk vaak: ontbrekende labels, onduidelijke foutafhandeling, slecht focusbeheer na submit en onbetrouwbare ARIA-implementaties zorgen dat schermlezers en toetsenbordgebruikers vastlopen. Dit leidt tot conversieverlies en juridisch risico.
Wij vertalen WCAG-richtlijnen naar concrete, testbare patterns: complete HTML-voorbeelden, CSS voor zichtbare focus, en JavaScript voor fout- en focusmanagement die je direct in productie kunt gebruiken. Test je pagina meteen met onze WCAG checker/validator en download onze plugin voor automatische scans; bij vragen reageren we binnen 24 uur via het contactformulier.
Het probleem in de praktijk
Ontbrekende of foutieve label-associatie
Veel ontwikkelaars vergeten <label>
of gebruiken placeholder als label. Resultaat: schermlezers zien velden niet correct en toetsenbordgebruikers missen context.
Onvoldoende foutinformatie en focus naar foutsummary
Fouten worden vaak alleen visueel aangegeven of met alert-boxen die niet door schermlezers worden opgepikt. Na submit blijft de focus op de knop, in plaats van naar een foutoverzicht te springen.
Slechte focusstyles en tabindex-misbruik
Custom focus-styling wordt weggelaten of tabindex wordt onnodig gebruikt waardoor tab-volgorde breekt en keyboard-ervaringen falen.
Zo los je dit op in code
Basale, correcte HTML-structuur met labels en fieldset
<form id="signup" novalidate><fieldset><legend>Aanmelden nieuwsbrief</legend><div class="form-row"><label for="email">E-mailadres</label><input id="email" name="email" type="email" required aria-required="true" aria-describedby="emailHelp emailError"><div id="emailHelp" class="sr-only">We gebruiken je e-mail alleen voor nieuws</div><div id="emailError" class="error" aria-live="polite"></div></div><div class="form-row"><label for="agree"><input id="agree" name="agree" type="checkbox" required aria-required="true"> Ik ga akkoord met de voorwaarden</label><div id="agreeError" class="error" aria-live="polite"></div></div><div id="formErrors" class="error-summary" role="alert" aria-live="assertive" tabindex="-1"></div><button type="submit">Aanmelden</button></fieldset></form>
CSS: zichtbare en consistente focus
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);border:0;}input:focus,button:focus,select:focus{outline:3px solid #0b66ff;outline-offset:2px;border-radius:3px;}button:focus{box-shadow:0 0 0 3px rgba(11,102,255,0.15);} /* geen tabindex styling override */
JavaScript: valideren, foutsummary vullen en focus verplaatsen
document.getElementById('signup').addEventListener('submit',function(e){e.preventDefault();const form=this;let errors=[];const email=form.querySelector('#email');const agree=form.querySelector('#agree');const formErrors=document.getElementById('formErrors');document.querySelectorAll('.error').forEach(el=>el.textContent='');if(!email.value||!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)){errors.push({field:email,id:'emailError',msg:'Vul een geldig e‑mailadres in.'});}if(!agree.checked){errors.push({field:agree,id:'agreeError',msg:'Je moet akkoord gaan met de voorwaarden.'});}if(errors.length){const ul=document.createElement('ul');errors.forEach(err=>{const li=document.createElement('li');const a=document.createElement('a');a.href='#'+err.field.id;a.textContent=err.msg;a.addEventListener('click',function(ev){ev.preventDefault();err.field.focus();});li.appendChild(a);ul.appendChild(li);document.getElementById(err.id).textContent=err.msg;});formErrors.innerHTML='<h2>Verwerk de volgende fouten</h2>';formErrors.appendChild(ul);formErrors.focus();return;} /* Succes: stuur met fetch of reguliere submit */form.submit();});
ARIA: wanneer en hoe gebruiken
Gebruik ARIA alleen als native HTML niet volstaat. Voor foutsummary gebruik role=”alert” of aria-live=”assertive” en zet tabindex=”-1″ op het error container element zodat je er programmatic focus naar kunt zetten (zie JS voorbeeld).
Checklist voor developers
Formulieren: de snelle checklist
- Elke input heeft een gerelateerde <label for=”id”> of aria-label/aria-labelledby als er geen zichtbare label is.
- Gebruik fieldset & legend voor groepen (radio/checkboxgroepen).
- Gebruik type attributen (email, tel, url) en required/aria-required waar van toepassing.
- Geef foutmeldingen zowel visueel als via aria-live/role=”alert”.
- Verplaats focus naar foutsummary met tabindex=”-1″ en element.focus().
- Geen tabindex>0 tenzij strikt noodzakelijk; volg natuurlijke DOM-volgorde.
- Vermijd presentational ARIA (role=”button” op echte button) en repareer in plaats van dupliceren.
Performance en progressive enhancement
Implementeer client-side validatie als progressive enhancement; server-side validatie moet dezelfde ARIA- en focus-routines aanroepen zodat foutmeldingen consistent zijn.
Tips voor designers en redacties
Visuele prioriteit en microcopy
Zorg dat foutteksten kort, actiegericht en vlakbij het veld staan. Gebruik visuele kleur + teksticon en altijd een tekstuele foutmelding (geen kleur alleen).
Layout en focusruimte
Reserveer voldoende ruimte voor foutmeldingen zodat content niet verschuift tijdens validatie. Zorg dat focusstijl goed zichtbaar is in het ontwerp (contrast, grootte).
Redactie workflow
Gebruik content templates met duidelijk label-velden en beschrijvingen. Instrueer redacteuren om placeholders niet als enige label te gebruiken.
Hoe test je dit?
Handmatige toetsenbordtest
- Tab door het formulier en controleer tab-volgorde en zichtbare focus.
- Leave required velden leeg en probeer te submitten; focus moet naar foutsummary gaan en links moeten naar de velden springen.
Screenreader-test
- Gebruik NVDA, JAWS of VoiceOver. Luister of labels voor elk veld worden voorgelezen en of foutmeldingen worden aangekondigd.
- Controleer aria-describedby en live regions.
Automatische tests
Integreer tools zoals axe-core, pa11y of onze WCAG checker/validator in CI. Gebruik onze plugin om je CMS-pagina’s automatisch te scannen en volg problemen in backlog.
Concrete teststappen met onze tool
Ga naar WCAG checker/validator, voer je URL in en kies “Form Validation & Focus” scan. Download de foutenlijst, pas de hierboven beschreven fixes toe en her-test via onze plugin (download: WCAGtool plugin). Vragen? Gebruik ons contactformulier — we reageren binnen 24 uur.
Extra concrete voorbeelden
Inline error + aria-invalid
<input id="phone" name="phone" type="tel" aria-invalid="true" aria-describedby="phoneError"><div id="phoneError">Voer een geldig telefoonnummer in</div>
Error summary link naar veld
<div id="formErrors" role="alert" tabindex="-1"><ul><li><a href="#email">E-mail ontbreekt of is niet geldig</a></li></ul></div>
Skip link implementatie
<a class="skip-link" href="#main" style="position:absolute;left:-999px;top:auto;" onfocus="this.style.left='0';" onblur="this.style.left='-999px';">Direct naar hoofdinhoud</a>
Laatste praktische tip
Voer direct een scan uit met onze WCAG checker/validator, installeer de plugin voor continue detectie en stuur vragen via het contactformulier — antwoord binnen 24 uur. Kopieer en plak dit minimale testscript in je console om te checken of foutsummary focus werkt:
const e=document.getElementById('formErrors');if(e){e.focus();console.log('Focus naar error summary gezet');}else{console.log('Geen error summary gevonden');}