Interactiecomponenten zoals modals, custom dropdowns, tabs en menu’s gaan in de praktijk vaak mis door onjuiste focusmanagement, verkeerde ARIA-toewijzingen en keyboard-tekortkomingen. Dit leidt tot keyboard-traps, onzichtbare focus of verwarrende screenreader-ervaringen — veel voorkomende WCAG-overtredingen bij real-world implementaties.
Wij lossen dit op met concrete, stap-voor-stap implementaties: duidelijke codevoorbeelden (HTML/CSS/JS + ARIA), testinstructies en checklists die je direct kunt toepassen. Test je site meteen met onze WCAG checker, download onze plugin via Download plugin en bij vragen: gebruik ons contactformulier — we reageren binnen 24 uur.
Het probleem in de praktijk
Veelvoorkomende fouten
- Custom controls missen keyboard support (Tab, Enter, Space, Arrow keys).
- Focus blijft buiten zicht of wordt niet logisch verplaatst bij openen/sluiten van modals.
- ARIA attributen zijn verkeerd gebruikt (role mismatch, aria-hidden on focusable elements).
- Visuele focus-indicatoren zijn verwijderd of niet zichtbaar bij hoge contrast-modus.
Waarom dit gebruikers daadwerkelijk blokkeert
Screenreader- en keyboard-only gebruikers hebben afhankelijkheid van semantiek en focus. Zonder correcte focus-returns en trap-beheer zijn functies onbereikbaar; zonder juiste ARIA wordt de interface onbegrijpelijk voor AT (assistive technologies).
Zo los je dit op in code
Algemene regels (altijd toepassen)
- Prefer native elements (<button>, <input>, <a>) boven custom divs. Native elementen brengen automatisch keyboard en ARIA support.
- Gebruik tabindex=”0″ om focus-toegankelijkheid toe te voegen, tabindex=”-1″ voor programma-matig focuseren.
- Voeg duidelijke focus-styling toe met :focus en focus-visible.
Voorbeeld: toegankelijke modal (HTML + CSS + JS)
<!-- HTML --><br><button id="openModal">Open modal</button><br><div id="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" aria-hidden="true"><br> <h2 id="modalTitle">Modal titel</h2><br> <button id="closeModal">Sluit</button><br> <div>Inhoud...</div><br></div>
<!-- CSS: zichtbare focus --><br>#modal {display:none;}<br>#modal[aria-hidden="false"] {display:block;}<br>button:focus, [tabindex]</*>:focus {outline:3px solid #005fcc; outline-offset:2px;}<br>.sr-only {position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden;}
<!-- JS: open/close + focus trap + restore focus --><br>const openBtn = document.getElementById('openModal');<br>const modal = document.getElementById('modal');<br>const closeBtn = document.getElementById('closeModal');<br>let lastFocused = null;<br>function openModal(){ lastFocused = document.activeElement; modal.setAttribute('aria-hidden','false'); modal.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])').focus(); document.addEventListener('keydown', trapTabKey); document.body.style.overflow = 'hidden';}<br>function closeModal(){ modal.setAttribute('aria-hidden','true'); document.removeEventListener('keydown', trapTabKey); document.body.style.overflow = ''; if(lastFocused) lastFocused.focus();}<br>function trapTabKey(e){ if(e.key !== 'Tab') return; const focusable = Array.from(modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])')).filter(el=> !el.hasAttribute('disabled')); const first = focusable[0]; const 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(); }}<br>openBtn.addEventListener('click', openModal); closeBtn.addEventListener('click', closeModal); modal.addEventListener('click', e => { if(e.target === modal) closeModal(); });
Uitleg key punten
- aria-modal=”true” + role=”dialog” vertelt AT dat dit een modal is.
- aria-hidden schakelt zichtbaarheid uit voor screenreaders wanneer gesloten.
- TrapTabKey voorkomt dat keyboard-gebruikers buiten de modal tabben.
- Restore focus (lastFocused.focus()) brengt gebruikers terug naar de juiste context.
Mini-how-to: custom dropdown met arrow-key support
<!-- HTML --><br><div class="dropdown" data-open="false"><br> <button class="toggle" aria-haspopup="listbox" aria-expanded="false" id="dd1">Kies optie</button><br> <ul role="listbox" tabindex="-1" aria-labelledby="dd1" hidden><br> <li role="option">Option 1</li><br> <li role="option">Option 2</li><br> <li role="option">Option 3</li><br> </ul><br></div>
<!-- JS: keyboard handlers --><br>const toggle = document.querySelector('.dropdown .toggle');<br>const list = document.querySelector('.dropdown [role=\"listbox\"]');<br>const options = Array.from(list.querySelectorAll('[role=\"option\"]'));<br>toggle.addEventListener('click', ()=>{ const open = toggle.getAttribute('aria-expanded') === 'true'; toggle.setAttribute('aria-expanded', String(!open)); list.hidden = open; if(!open){ list.focus(); } });<br>list.addEventListener('keydown', e => { const idx = options.indexOf(document.activeElement); if(e.key === 'ArrowDown'){ e.preventDefault(); const next = options[(idx+1) % options.length]; next.focus(); } if(e.key === 'ArrowUp'){ e.preventDefault(); const prev = options[(idx-1+options.length) % options.length]; prev.focus(); } if(e.key === 'Enter' || e.key === ' '){ e.preventDefault(); selectOption(document.activeElement); } if(e.key === 'Escape'){ toggle.focus(); toggle.click(); }}); options.forEach(o => o.setAttribute('tabindex','-1')); options[0].setAttribute('tabindex','0'); function selectOption(el){ toggle.textContent = el.textContent; toggle.setAttribute('aria-expanded','false'); list.hidden = true; toggle.focus(); }
Checklist voor developers
- Gebruik native elementen waar mogelijk.
- Controleer en test Tab-volgorde logisch met alleen keyboard.
- Voeg :focus-visible styling toe en verwijder outline: none niet zonder alternatief.
- Gebruik aria-modal voor modals, role=”dialog” en beheer aria-hidden correct.
- Voorkom keyboard traps: implementeer focus trap & restore focus.
- Maak custom widgets keyboard-navigable (Enter/Space en Arrow keys).
- Valideer ARIA attributen met de WCAG checker.
Tips voor designers en redacties
Visuele focus & ontwerpregels
- Ontwerp duidelijke focus-indicatoren: kleur, contrast en grootte; test op minimale contrast-ratio.
- Beschrijf in component-specs de keyboard-interacties en visuele focus-states.
Content richtlijnen
- Gebruik duidelijke labels en aria-labels alleen als zichtbare tekst niet mogelijk is.
- Vermijd het verbergen van text-only labels met aria-hidden; screenreaders moeten altijd betekenis krijgen.
Hoe test je dit?
Handmatige keyboard-tests (stap-voor-stap)
- Schakel muis uit of leg de hand niet op muis: navigeer alleen met Tab en Shift+Tab door de pagina. Alle interactieve items moeten bereikbaar en logisch geordend zijn.
- Test modals: open, tab door alle controls, probeer Escape en klikken buiten de modal. Focus mag niet buiten de modal springen.
- Test custom widgets: Arrow keys, Enter/Space voor selectie, Escape om te sluiten. Screenreader-behavior controleren met NVDA/VoiceOver/JAWS.
Automated checks en tooling
- Gebruik onze WCAG checker voor snelle scans en rapporten.
- Installeer de WCAGTool browser plugin voor on-page adviezen tijdens development.
- Voer axe-core en Lighthouse audits uit in CI; creëer failing tests op kritieke a11y-regels.
Concrete testscript voor QA
1. Open pagina. 2. Tab door alle focusbare controls—controleer focus zichtbaar. 3. Open modal—controleren aria-hidden verandert, focus in modal. 4. Probeer Shift+Tab tot begin: focus blijft in modal. 5. Sluit modal met Esc en met Close knop; focus terug op opener. 6. Test custom dropdown: Enter opent, Arrow navigatie, Enter selecteert.
Extra resources en support
Run direct een scan met onze WCAG checker en krijg concrete foutlocaties en code-aanpassingen. Download onze plugin voor on-page aanwijzingen: Download plugin. Vragen? Gebruik het contactformulier — we reageren binnen 24 uur en helpen met concrete code-aanpassingen.
Praktische tip: voeg tijdens development in je base CSS een zichtbare focus-stijl toe zodat elk teamlid direct regressies ziet. Kopieer deze regel in je stylesheet:
:focus { outline: 3px solid #005fcc; outline-offset: 2px; }
Direct toepasbare check: test één pagina nu met onze WCAG checker, installeer de plugin en stuur bij vragen een bericht via ons contactformulier — antwoord binnen 24 uur.