Succescriteria: hoe werken A, AA en AAA?

WCAG-praktijk: Toegankelijk toetsenbordgebruik en focusbeheer — wcagtool.nl

Toegankelijk toetsenbordgebruik en focusbeheer

Toetsenbordtoegankelijkheid en correct focusbeheer falen in veel projecten: ontbrekende keyboard-events op custom controls, slechte focus‑visibiliteit, modals die focus lekken en verkeerde tabindex-strategieën. Dat leidt direct tot onbruikbaarheid voor screenreader- en toetsenbordgebruikers en levert vaak failed WCAG-criteria op.

Wij helpen je praktisch: stap-voor-stap codevoorbeelden (HTML/CSS/JS), testinstructies en checklists die je meteen kunt toepassen. Test je site direct met onze WCAG checker/validator, download onze plugin en vraag ons advies via het contactformulier (reactie binnen 24 uur).

Het probleem in de praktijk

Hier de meest voorkomende fouten die we in audits tegenkomen:

  • Custom elements (div/span) zonder role/tabindex/keyboard handling.
  • Verbergen van focus outlines door CSS (outline: none) zonder alternatief zichtbaar focus-styling.
  • Modals/dialogs die focus niet trapten — achterliggende pagina blijft tabbaar.
  • Roving tabindex verkeerd geïmplementeerd bij menus en toolbar widgets.
  • Geen skip-link of skip-link onzichtbaar voor toetsenbordgebruikers.

Zo los je dit op in code

1) Basisregels: gebruik semantische elementen

Gebruik native controls als het kan: <button>, <a href>, <input>. Pas pas ARIA toe als er geen native equivalent is.

2) Maak custom controls keyboard toegankelijk

Voor custom knop-achtige elementen:

<!-- HTML --><div class="custom-btn" role="button" tabindex="0" aria-pressed="false">Actie</div>
/* CSS: zichtbare focus */.custom-btn:focus{outline:3px solid #2b7cff;outline-offset:2px;border-radius:4px}
// JavaScript: Enter/Space activeren en ARIA bijwerkendocument.addEventListener('keydown', function(e){var t = e.target;if(t.classList && t.classList.contains('custom-btn')){if(e.key === 'Enter' || e.key === ' '){e.preventDefault();t.click();}}});document.querySelectorAll('.custom-btn').forEach(function(btn){btn.addEventListener('click', function(){var pressed = btn.getAttribute('aria-pressed') === 'true';btn.setAttribute('aria-pressed', String(!pressed));});});

3) Skip-link implementeren

<a class="skip-link" href="#main-content">Sla navigatie over</a><main id="main-content">...
/* CSS: zichtbaar bij focus */.skip-link{position:absolute;left:-9999px}.skip-link:focus{position:relative;left:0;top:0;background:#fff;color:#000;padding:8px;z-index:1000}

4) Focus-visible: gebruik :focus-visible of polyfill

/* Voorkom dat muisklik outline zichtbaar wordt, maar laat keyboard focus zien */:focus{outline: none} :focus-visible{outline: 3px solid #2b7cff;outline-offset: 2px}

5) Focus management bij modals (focus trap)

Essentieel: zet focus in de modal bij openen, trap tab binnen modal, restore focus bij sluiten.

// Eenvoudige focus trapfunction trapFocus(container){var focusable = container.querySelectorAll('a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])');if(!focusable.length) return;var first = focusable[0];var last = focusable[focusable.length-1];function handle(e){if(e.key !== 'Tab') return;if(e.shiftKey && document.activeElement === first){e.preventDefault();last.focus();} else if(!e.shiftKey && document.activeElement === last){e.preventDefault();first.focus();}}container.addEventListener('keydown', handle);return function release(){container.removeEventListener('keydown', handle);};}
// Gebruik bij modalopenvar releaseTrap = trapFocus(myModal);myModal.querySelector('.close').addEventListener('click', function(){releaseTrap();previousFocus && previousFocus.focus();});

6) Focus herstellen na dynamic content

// Na AJAX update: zet focus op kop of nieuw itemvar target = document.getElementById('nieuw-item');target.setAttribute('tabindex','-1');target.focus(); // optioneel: remove tabindex later

7) Roving tabindex voor keyboard-only menu’s

// HTML voorbeeld<ul role="toolbar"><li role="button" tabindex="0">Optie 1</li><li role="button" tabindex="-1">Optie 2</li></ul>
// JS: manage left/right arrowsvar items = Array.from(toolbar.querySelectorAll('[role="button"]'));items.forEach(function(it,index){it.addEventListener('keydown', function(e){if(e.key==='ArrowRight'){e.preventDefault();var next = items[(index+1)%items.length];it.setAttribute('tabindex','-1');next.setAttribute('tabindex','0');next.focus();} if(e.key==='ArrowLeft'){e.preventDefault();var prev = items[(index-1+items.length)%items.length];it.setAttribute('tabindex','-1');prev.setAttribute('tabindex','0');prev.focus();}});});

Checklist voor developers

  • Gebruik semantische elementen waar mogelijk.
  • Alle interactieve elementen zijn focusable en reageren op Enter/Space.
  • Zichtbare focus-stijlen: test met keyboard only.
  • Modals trappen focus en herstellen focus bij sluiten.
  • Roving tabindex logisch en consistent geïmplementeerd.
  • Geen elements met tabindex>0 in productie (vermijd complexiteit).
  • Beperk gebruik van aria-live voor tijdelijke updates en maak changes announceable.
  • Automatiseer checks met onze WCAG checker en browser extensie/plugin.

Tips voor designers en redacties

Designers: focusstijl en contrast

Zorg dat focuscontrasten voldoen aan WCAG (tegen achtergrondkleur). Voorzie duidelijke focus-voorbeelden in component library en ontwerp states voor focus, hover en active.

Redacties: inhoud en taborder

Bij dynamische content (toegankelijke tabs, accordions) altijd focus verplaatsen naar relevante kop/taak en zet aria-expanded/aria-controls correct. Test of content ook bereikbaar is zonder muis en dat skip-links logisch zijn geplaatst.

Hoe test je dit?

1) Handmatige toetsenbordtests

  • Start met tab: kun je alle interactieve items bereiken in logische volgorde?
  • Gebruik Shift+Tab: werkt de terug-naar-voorgaande focus correct?
  • Open modal met keyboard en controleer of focus niet naar achterliggende pagina kan springen.
  • Activeer custom controls met Enter en Space en controleer aria-attributes.

2) Screenreader checks

  • Juiste roles en aria-labels? Test met NVDA/VoiceOver of control-labels goed worden aangekondigd.
  • Bij dynamische updates: worden wijzigingen geannonceerd? Gebruik aria-live region indien nodig.

3) Geautomatiseerde tools

Run onze WCAG checker/validator en browser plugin. Combineer met Axe-core tijdens CI-builds en Lighthouse voor regressiecontrole.

4) Snelle testcases die je direct kunt uitvoeren

  1. Remove mouse: gebruik enkel toetsenbord en voer basis flow uit (inloggen, navigeren, formulier invullen).
  2. Modal test: open modal, tab door elementen, sluit modal en controleer focusherstel.
  3. Custom control test: focus op custom element, Enter/Space en controleer aria-wijzigingen.

Concrete codevoorbeelden en utilities

Utility: setFocus(element)

function setFocus(el){if(!el) return;el.setAttribute('tabindex','-1');el.focus();el.addEventListener('blur', function r(){el.removeAttribute('tabindex');el.removeEventListener('blur', r);});}

Utility: makeClickableDivAccessible

function makeClickableDivAccessible(el, onActivate){el.setAttribute('role','button');el.setAttribute('tabindex','0');el.addEventListener('keydown', function(e){if(e.key==='Enter' || e.key===' '){e.preventDefault();onActivate(e);}});el.addEventListener('click', onActivate);}

ARIA-live voorbeeld voor statusmeldingen

<div id="status" aria-live="polite" class="sr-only"></div>// updatestatusdocument.getElementById('status').textContent = 'Opslaan voltooid';

Laatste praktische tip

Voeg direct deze snelle sanity-check snippet toe aan je devtools console om keyboard-issues te vinden: het markeert elementen zonder focus-stijlen en geeft advies.

(function(){var els = document.querySelectorAll('a,button,input,textarea,select,[role="button"],[tabindex]');els.forEach(function(el){var style = window.getComputedStyle(el);if(style.outlineStyle==='none' && style.boxShadow==='none'){el.style.boxShadow='0 0 0 3px rgba(43,124,255,0.4)';el.setAttribute('data-wcagtool-focus-suggest','true');}});console.log('WCAGTool quick keyboard sanity check applied. Test keyboard navigation and run https://wcagtool.nl/checker');})();

Test je website nu met onze WCAG checker, download de plugin voor je browser en stel technische vragen via ons contactformulier (antwoord binnen 24 uur). Gebruik de snippet hierboven direct in de console en verbeter focusbeheer stap voor stap.

Previous Post Next Post

Geef een reactie

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