WCAG versiegeschiedenis: van 1.0 naar 3.0

Praktische WCAG-implementatie — formulieren, focus en dynamische content | WCAGtool.nl

Introductie: In de praktijk gaat het bij WCAG-implementatie vaak mis bij formulieren, focusmanagement en dynamische content: velden missen labels, foutmeldingen zijn onzichtbaar voor screenreaders en modals blokkeren toetsenbordgebruik. Ontbrekende standaardpatronen en incomplete ARIA-implementaties leiden tot onnodige toegankelijkheidsproblemen die makkelijk te voorkomen zijn.

Wij leveren concrete, testbare oplossingen met stap-voor-stap codevoorbeelden en checklists die je direct in productie kunt inzetten. Test je werk realtime met onze WCAG checker, installeer onze plugin via https://wcagtool.nl/plugin en stel vragen via https://wcagtool.nl/contact — wij reageren binnen 24 uur.

Het probleem in de praktijk

Veelvoorkomende fouten

  • Labels ontbreken of zijn visueel geplaatst zonder ‘for’ attributen.
  • Foutmeldingen zijn expliciet voor visueel, maar niet voor screenreaders (geen aria-live).
  • Modal dialogs en menu’s breken keyboard focus of ontbreken focustrap.
  • Contrast en focus styles zijn onvoldoende zichtbaar.
  • Dynamische updates missen semantische indicatie (aria-live, role=”status”).

Waarom simpele oplossingen falen

Ontbreken van semantische HTML wordt vaak geprobeerd op te lossen met ad-hoc ARIA-attributen zonder de onderliggende structuur te volgen. Resultaat: inconsistent gedrag in screenreaders en mobiele browsers. Wij focussen op eerst semantiek, dan ARIA, daarna styling en tests.

Zo los je dit op in code

1) Formulieren: correcte labels, foutafhandeling en focus

Stap 1: gebruik semantic <label> gekoppeld via for/id. Stap 2: voeg aria-describedby toe aan input voor aanvullende uitleg of foutmelding. Stap 3: bij validatie: focus op het eerste foutveld en zet fouttekst in een aria-live container.

<form id="signup" novalidate><div><label for="email">E-mail</label><input id="email" name="email" type="email" aria-describedby="emailHelp emailError"><small id="emailHelp">We sturen een bevestiging.</small><div id="emailError" role="alert" aria-live="assertive" class="error" hidden>Vul een geldig e-mailadres in.</div></div><button type="submit">Aanmelden</button></form>

JS-validatie (focus op eerste fout):

document.getElementById('signup').addEventListener('submit',function(e){e.preventDefault();var email=document.getElementById('email');var error=document.getElementById('emailError');if(!/^\S+@\S+\.\S+$/.test(email.value)){error.hidden=false;error.textContent='Vul een geldig e-mailadres in.';email.focus();}else{error.hidden=true;/* submit form via Ajax of normale submit */}});

2) Modal dialog met focus trap (keyboard toegankelijk)

Essentieel: role=”dialog”, aria-modal=”true”, focus trap en herstel focus bij sluiten.

<button id="openModal">Open</button><div id="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" hidden><h2 id="modalTitle">Titel</h2><button id="closeModal">Sluiten</button></div>
const open=document.getElementById('openModal');const modal=document.getElementById('modal');const closeBtn=document.getElementById('closeModal');let lastFocus=null;open.addEventListener('click',()=>{lastFocus=document.activeElement;modal.hidden=false;modal.setAttribute('tabindex','-1');modal.focus();document.addEventListener('keydown',trap);});closeBtn.addEventListener('click',close);function trap(e){if(e.key==='Escape'){close()}if(e.key==='Tab'){const focusable=Array.from(modal.querySelectorAll('a[href],button:not([disabled]),input,select,textarea,[tabindex]:not([tabindex=\"-1\"])'));if(!focusable.length) {e.preventDefault();return;}const first=focusable[0],last=focusable[focusable.length-1];if(e.shiftKey && document.activeElement===first){e.preventDefault();last.focus();}else if(!e.shiftKey && document.activeElement===last){e.preventDefault();first.focus();}}}function close(){modal.hidden=true;modal.removeAttribute('tabindex');document.removeEventListener('keydown',trap);if(lastFocus) lastFocus.focus();}

3) Dynamische content en ARIA-live

Voor updates (notificaties, foutmeldingen, search results) gebruik aria-live regions met passende politeness.

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

4) Focus styles en visible focus

Gebruik :focus-visible, maar zorg voor fallback. Verwijder nooit outline zonder alternatief.

button:focus-visible, a:focus-visible{outline:3px solid #1a73e8;outline-offset:3px;}button:focus{box-shadow:0 0 0 3px rgba(26,115,232,0.2);} 

5) Toegankelijke toetsenbordnavigatie voor custom components

Voor custom dropdowns: role=”listbox”, aria-activedescendant, manage arrow keys, Enter en Escape.

<div role="listbox" id="countryList" tabindex="0" aria-activedescendant="opt-0"><div id="opt-0" role="option" aria-selected="true">Nederland</div><div id="opt-1" role="option">België</div></div>
const list=document.getElementById('countryList');list.addEventListener('keydown',e=>{const items=Array.from(list.querySelectorAll('[role=\"option\"]'));let index=items.findIndex(i=>i.id===list.getAttribute('aria-activedescendant'));if(e.key==='ArrowDown'){e.preventDefault();index=(index+1)%items.length;select(index);}if(e.key==='ArrowUp'){e.preventDefault();index=(index-1+items.length)%items.length;select(index);}if(e.key==='Enter'){e.preventDefault();choose(items[index]);}function select(i){items.forEach(it=>it.setAttribute('aria-selected','false'));items[i].setAttribute('aria-selected','true');list.setAttribute('aria-activedescendant',items[i].id);items[i].scrollIntoView({block:'nearest'});}function choose(item){console.log('Gekozen',item.textContent);}}

Checklist voor developers

  • Gebruik semantische HTML vóór ARIA: <button> <nav> <main> <header> <label>.
  • Koppel labels aan inputs met for/id.
  • Geef foutmeldingen role=”alert” of plaats in aria-live region.
  • Zorg dat modals focus trap hebben en Escape werken.
  • Test keyboard-only: Tab, Shift+Tab, Enter, Space, Escape, Arrow keys.
  • Contrast: minimaal 4.5:1 voor tekst; controleer via onze checker.
  • Voeg zichtbare focusstyles toe en verwijder outline nooit zonder alternatief.
  • Controleer dynamische updates met aria-live en aria-atomic.

Tips voor designers en redacties

Headings en contentstructuur

Gebruik h1–h6 hiërarchie logisch. Gebruik korte, beschrijvende linkteksten (“Lees meer” vermijden). Zorg dat belangrijke content niet alleen via kleur wordt gecommuniceerd.

Afbeeldingen en media

Alt-tekst: kort, beschrijvend en functioneel; decoratieve afbeeldingen met alt=”” en role=”presentation”. Voor video: ondertiteling en transcript beschikbaar maken.

Formuliercopy en inline hulp

Geef voorbeeldformaten, valideer inline en verplaats focus bij foutmelding naar het eerste foutveld. Redacties: gebruik consistente foutformuleringen en vermijd jargon.

Design tokens en contrast

Definieer kleur- en spacing-tokens, test elke component op contrast en focusgrootte. Gebruik onze plugin voor design-systeemchecks: Download plugin.

Hoe test je dit?

Automatisch en handmatig combineren

Gebruik eerst onze WCAG checker voor snelle issues (contrast, missing alt, ARIA errors). Automatiseer met CI/CD en de plugin. Manual check alsnog noodzakelijk voor keyboard en screenreader flows.

Keyboard-only test (stappen)

  1. Schakel muis uit of leg hem weg.
  2. Tab door de pagina: zijn alle focusbare items zichtbaar en logisch gesorteerd?
  3. Bedien alle interactieve elementen met Enter/Space en navigatiecomponenten met pijltoetsen.
  4. Probeer modal openen/sluiten en focus herstel.

Screenreader-test (stappen)

  1. Installeer NVDA (Windows) of VoiceOver (Mac/iOS).
  2. Luister naar page title, headings en live regions.
  3. Activeer formulierfouten en controleer of foutmelding wordt voorgelezen en focus verplaatst.

End-to-end testpunten

  • Automateer contrast en linting in CI met our plugin.
  • Schrijf e2e-tests die toetsenbordflows simuleren (Cypress, Playwright).
  • Voeg screenreader smoke tests toe (Pa11y/axe in CI).

Test je site nu direct met onze WCAG checker. Heb je vragen? Gebruik ons contactformulier — antwoord binnen 24 uur.

Laatste praktische tip

Voeg direct deze snippet toe om foutmeldingen altijd voor screenreaders zichtbaar te maken en focus te sturen naar het eerste foutveld:

/* Insert in je script */function showFieldError(inputId,message){const input=document.getElementById(inputId);const errId=inputId+'-err';let err=document.getElementById(errId);if(!err){err=document.createElement('div');err.id=errId;err.setAttribute('role','alert');err.setAttribute('aria-live','assertive');err.className='error';input.insertAdjacentElement('afterend',err);}err.textContent=message;input.setAttribute('aria-describedby',errId);input.focus();}

Direct testen? Start met https://wcagtool.nl/checker, installeer de plugin via https://wcagtool.nl/plugin en bij vragen gebruik https://wcagtool.nl/contact — wij reageren binnen 24 uur.

Previous Post Next Post

Geef een reactie

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