ARIA: juiste toepassing en veelgemaakte fouten

Toegankelijke formulieren en foutmeldingen — Praktische implementatie | WCAGtool

Toegankelijke formulieren en foutmeldingen: direct toepassen

Formulieren zijn in de praktijk een van de grootste bronnen van WCAG-fouten: ontbrekende labels, ontoegankelijke foutmeldingen, slechte focusbeheer en onduidelijke ARIA-implementaties zorgen voor onbruikbaarheid voor mensen met screenreaders en toetsenbordgebruikers. Ontwerpers en developers negeren vaak edge-cases (inline fouten, file uploads, datepickers) waardoor conversie en toegankelijkheid tegelijk kelderen.

Wij bij WCAGtool.nl maken formulieren wél bruikbaar: duidelijke patronen, testbare code-snippets en stappenplannen die je meteen kunt inzetten. Test je pagina direct met onze WCAG checker/validator, download onze plugin via wcagtool.nl/plugin en vraag advies via ons contactformulier — we reageren binnen 24 uur.

Het probleem in de praktijk

Veelvoorkomende fouten

  • Labels ontbreken of zijn niet gekoppeld met for/id.
  • Foutmeldingen zijn visueel maar niet programmeerbaar (geen aria-live, geen aria-describedby).
  • Geen foutoverzicht met focusverschuiving naar het eerste probleem.
  • Custom widgets (datepickers, fileuploaders) missen keyboard support en ARIA roles.
  • ARIA-attributen verkeerd gebruikt: aria-hidden op verkeerde elementen, aria-live op statische content.

Waarom dit vaak fout gaat

Developers vertrouwen op visuele styling en client-side libraries zonder de ARIA- en semantische fallback te implementeren. Designers leveren visueel duidelijkere fouten, maar vergeten beschrijvende teksten voor screenreaders en redacties plaatsen onduidelijke foutfraseringen.

Zo los je dit op in code

1) Basispatroon: correcte label-associatie

Altijd for + id of een wrapping label gebruiken. Voor radio/checkbox groepen: use fieldset + legend.

<label for="email">E-mailadres</label><br><input id="email" name="email" type="email" required aria-describedby="emailHelp"><br><small id="emailHelp">Gebruik je werk- of privé-e-mail</small>

2) Inline foutmelding met aria-describedby en aria-invalid

Markeer invalid en koppel fouttekst via aria-describedby. Zorg dat fouttekst zichtbaar en programmeerbaar is.

<input id="phone" name="phone" type="tel" aria-invalid="true" aria-describedby="phone-error"><br><span id="phone-error" role="alert">Voer een geldig telefoonnummer in</span>

3) Foutoverzicht bovenaan (error summary) met focus management

Toegankelijke pattern: verzamel server- of client-side errors en toon een samenvatting boven het formulier. Zet focus op die samenvatting en geef links/anchors naar individuele velden.

<div id="error-summary" role="alert" tabindex="-1"><h2>Er zijn fouten in het formulier</h2><ul><li><a href="#email">E-mailadres ontbreekt</a></li></ul></div>

4) Focus verplaatsen programatisch (JS)

Verplaats focus naar de error-summary zodra formulier validatie faalt.

document.getElementById('form').addEventListener('submit',function(e){if(!this.checkValidity()){e.preventDefault();const summary=document.getElementById('error-summary');summary.focus();}});

5) Keyboard en ARIA voor custom widgets (datepicker voorbeeld)

Voor custom components: role, aria-expanded, aria-controls, keyboard handlers en roving tabindex.

<div class="datepicker" role="application"><button aria-haspopup="dialog" aria-expanded="false" id="dp-toggle">Open datumkiezer</button><div id="dp-dialog" role="dialog" aria-hidden="true">...kalender...",

6) CSS voor zichtbare focus (gebruik :focus-visible)

:focus-visible{outline:3px solid #ff9800;outline-offset:2px;}button:focus-visible{box-shadow:0 0 0 3px rgba(255,152,0,0.25);}

7) Server-side validatie en ARIA

Vertrouw nooit alleen op client-side. Stuur errors terug in JSON met field identifiers en genereer server-rendered error-summary en aria-describedby koppelingen. Voor SPAs: synchroniseer serverfouten naar de DOM en trigger focus op de error-summary.

// voorbeeld response: { "errors": { "email":"Ongeldig e-mailadres" } }

Checklist voor developers

  • Elke input heeft een label (for/id) of een ingesloten label.
  • Gebruik fieldset + legend voor logische groepen (radio/checkbox).
  • Voeg aria-describedby toe voor hulp- en foutteksten.
  • Gebruik aria-invalid=”true” op foutieve velden.
  • Toon een error-summary met role=”alert” en tabindex=”-1″ en verplaats daar focus na submit.
  • Zorg dat custom widgets keyboard-accessible zijn en correcte ARIA roles/attributes gebruiken.
  • Gebruik :focus-visible voor duidelijke focusstijlen zonder visuele ruis.
  • Valideer altijd ook server-side en mappen server-fouten terug naar toegankelijke UI.
  • Automatiseer checks met onze WCAG checker/validator en installeer onze plugin in je CI.

Tips voor designers en redacties

Schrijf duidelijke foutteksten

Formuler foutmeldingen actiegericht: “Voer een geldig e-mailadres in” is beter dan “Ongeldige invoer”. Voeg voorbeelden en acceptatiecriteria toe (bijv. formaat, lengte).

Design voor tekstuitbreiding

Houd rekening met langere foutteksten en vertalingen — test met +30% tekstlengte. Zorg dat foutboxen niet overlappen met andere content.

Visuele hiërarchie en kleurgebruik

Kleur alleen gebruiken als extra signaal. Combineer rood met icon en tekst. Zorg contrast >4.5:1 voor foutteksten en labels; controleer met onze contrasttool.

Hoe test je dit?

Automatisch scannen

  • Gebruik onze WCAG checker/validator voor een eerste scan (WCAG 2.1 AA checks + praktische aanbevelingen).
  • Plaats onze plugin in je CI: elke PR krijgt meteen toegankelijkheidsfeedback.

Handmatige checks (stap-voor-stap)

  1. Schakel alle CSS uit? Controleer label-to-field koppelingen met browser devtools.
  2. Toets formulier volledig uit met alleen toetsenbord: tab, shift+tab, enter, space; controleer zichtbare focus en keyboard operability van custom widgets.
  3. Gebruik een schermlezer (NVDA/VoiceOver): lees labels, helpteksten en foutmeldingen hardop; activeer invalide velden en verifieer dat errors aankondigen (aria-live/role=”alert”).
  4. Simuleer server-side fouten: stuur ongeldige data en controleer error-summary focus en links naar velden.
  5. Controleer contrast met onze validator en test tekstuitbreiding/zoom (200%).

Testscript dat je kunt gebruiken

// sneltest: keyboard + screenreader basics (voeg toe aan QA run)await page.goto('https://jouwsite.nl/form');await page.keyboard.press('Tab'); // alle interactables doorlopenawait expect(page).toHaveFocus('#email'); // controleer focuspositieawait page.click('#submit');await expect(page.locator('#error-summary')).toBeVisible();await expect(page.locator('#error-summary')).toHaveFocus();

Concrete mini-how-to’s

Hoe maak je een toegankelijke file upload

<label for="file">Upload CV</label><input id="file" name="file" type="file" aria-describedby="file-help file-error"><div id="file-help">PDF of DOC, max 5MB</div><div id="file-error" role="alert"></div>

Controleer bestandsgrootte en mime-type client- & server-side; toon fout in file-error en geef focus naar error-summary bij submit.

Hoe implementeer je aria-live voor realtime validatie

<div id="live-error" aria-live="polite" aria-atomic="true"></div>function showLiveError(msg){document.getElementById('live-error').textContent=msg;}

Voorbeeld volledige validatie (HTML + JS)

<form id="contact"><label for="name">Naam</label><input id="name" name="name" required><label for="email">E-mail</label><input id="email" name="email" type="email" required><button type="submit">Verstuur</button><div id="error-summary" role="alert" tabindex="-1" style="display:none"><h2>Er zijn fouten</h2><ul id="error-list"></ul></div></form><script>document.getElementById('contact').addEventListener('submit',function(e){e.preventDefault();const errors=[];const name=document.getElementById('name');const email=document.getElementById('email');if(!name.value.trim())errors.push({id:'name',msg:'Vul je naam in'});if(!/^\S+@\S+\.\S+$/.test(email.value))errors.push({id:'email',msg:'Ongeldig e-mailadres'});const summary=document.getElementById('error-summary');const list=document.getElementById('error-list');list.innerHTML='';if(errors.length){errors.forEach(err=>{const li=document.createElement('li');const a=document.createElement('a');a.href='#'+err.id;a.textContent=err.msg;li.appendChild(a);list.appendChild(li);const field=document.getElementById(err.id);field.setAttribute('aria-invalid','true');field.setAttribute('aria-describedby','error-'+err.id);let span=document.getElementById('error-'+err.id);if(!span){span=document.createElement('span');span.id='error-'+err.id;span.setAttribute('role','alert');field.insertAdjacentElement('afterend',span);}span.textContent=err.msg;});summary.style.display='block';summary.focus();return false;}else{summary.style.display='none';this.submit();}});</script>

Meer tools en hulp

Gebruik onze online validator voor snelle scans en gedetailleerde uitleg per issue. Installeer de CI-plugin om regressies te voorkomen. Voor projectadvies of hands-on implementatie kun je ons team bereiken via het contactformulier — wij reageren binnen 24 uur.

Test je formulier nu meteen: ga naar wcagtool.nl/validator, plak je URL en ontvang directe verbeterpunten.

Laatste praktische tip

Voeg dit korte snippet toe onderaan je formulier om altijd een toegankelijke error-summary te tonen en focus te zetten wanneer validatie faalt:

function showErrorSummary(errors){const s=document.getElementById('error-summary')||document.createElement('div');s.id='error-summary';s.setAttribute('role','alert');s.tabIndex=-1;s.innerHTML='<h2>Er zijn fouten</h2><ul>'+errors.map(e=>'<li><a href=\"#'+e.id+'\">'+e.msg+'</a></li>').join('')+'</ul>';document.querySelector('form').prepend(s);s.focus();}

Nog vragen? Test nu met onze WCAG checker/validator, download de plugin en neem contact op via ons contactformulier — antwoord binnen 24 uur.

Previous Post Next Post

Geef een reactie

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *