WCAG-versies uitgelegd: 2.0, 2.1, 2.2 en 3.0 vergeleken

Keyboard accessibility & focus management — praktische implementatie | WCAGTool

Keyboard accessibility & focus management — praktisch toepassen

Keyboard-toegankelijkheid en correct focusbeheer falen vaak in de praktijk omdat teams componenten bouwen zonder keyboard-events, verkeerde ARIA-toevoegingen of zonder duidelijke focusstijlen. Resultaat: interactieve elementen zijn onbereikbaar of onvoorspelbaar voor toetsenbordgebruikers en screenreadergebruikers.

Wij leggen stap-voor-stap uit hoe je components, formulieren en modals keyboard-proof maakt: semantic HTML, minimale en juiste ARIA, consistente tabindex-logica, zichtbare focus-stijlen en testbare procedures. Test direct met onze WCAG checker op wcagtool.nl/checker, download onze plugin op wcagtool.nl/plugin en bij vragen: contactformulier (antwoord binnen 24 uur).

Het probleem in de praktijk

Veelvoorkomende fouten:

  • Custom controls zonder native semantics (div/span in plaats van button) zonder keyboard handlers of aria.
  • Verkeerd gebruik van tabindex (tabindex=”0″ op te veel items of tabindex=”1″ etc.).
  • Geen focus management bij modals, dialogs en dynamische content.
  • Focus styles verwijderd door designers (outline: none) zonder alternatief.

Waarom dit direct impact heeft

WCAG 2.1.1 Keyboard, 2.4.3 Focus Order en 2.4.7 Focus Visible worden direct aangetast. Dit leidt tot onbruikbaarheid voor toetsenbord-only gebruikers en lagere scores in automatische validators — test met onze tool op wcagtool.nl/checker.

Zo los je dit op in code

Gebruik altijd semantische HTML als eerste keuze

Voorkeur: gebruik <button>, <a href>, <input> etc. Pas pas ARIA alleen toe als semantics ontbreken of uitbreidingen nodig zijn.

Voorbeeld: custom toggle — verkeerde aanpak

<div class="toggle" role="button" tabindex="0">Aan</div>

Correcte, testbare implementatie (HTML + JS + ARIA)

<button class="toggle" aria-pressed="false">Aan</button>
// JavaScript
document.querySelectorAll('.toggle').forEach(btn => {
  btn.addEventListener('click', () => {
    const pressed = btn.getAttribute('aria-pressed') === 'true';
    btn.setAttribute('aria-pressed', String(!pressed));
  });
});

Waarom dit werkt

Een echte <button> ondersteunt Enter/Space en focus out-of-the-box en screenreaders begrijpen aria-pressed. Geen extra keydown handlers nodig.

Keyboard handlers als fallback (alleen wanneer semantics niet mogelijk)

// Gebruik alleen als semantische tag niet beschikbaar is
element.setAttribute('role','button');
element.setAttribute('tabindex','0');
element.addEventListener('keydown', e => {
  if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); element.click(); }
});

Focus-visible: laat gebruikers zien waar de focus is

Gebruik de moderne :focus-visible selector en een tastbare fallback voor browsers zonder ondersteuning.

/* CSS */
:focus-visible { outline: 3px solid #005fcc; outline-offset: 2px; }
/* Fallback voor oudere browsers */
.js-focus .focus-ring:focus { outline: 3px solid #005fcc; }

Focus management bij modals

Regels:

  1. Trap focus binnen de modal.
  2. Stel focus op het eerste focusbare element of op de modal zelf.
  3. Herstel focus naar het element dat de modal opende.
// Minimal focus trap (conceptueel)
function trapFocus(modal) {
  const focusables = modal.querySelectorAll('a, button, input, textarea, select, [tabindex]:not([tabindex=\"-1\"])');
  const first = focusables[0]; const last = focusables[focusables.length - 1];
  function handleKey(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(); }
  }
  modal.addEventListener('keydown', handleKey);
  return () => modal.removeEventListener('keydown', handleKey);
}
// Gebruik: const release = trapFocus(myModal); release();

Skip-links: direct naar content springen

Voeg zichtbare skip-links toe die alleen in beeld verschijnen bij focus.

<a class="skip-link" href="#maincontent">Sla navigatie over</a>
.skip-link { position: absolute; left: -999px; }
.skip-link:focus { left: 10px; top: 10px; }

Checklist voor developers

  • Gebruik semantics vóór ARIA.
  • Geen tabindex>0/negatief zonder documentatie. Gebruik tabindex=”0″ alleen voor elements die normaal niet focusbaar zijn en tabindex=”-1″ voor programmatic focus.
  • Focus-visible altijd aanwezig (gebruik :focus-visible, geen outline: none zonder alternatief).
  • Modals: trap focus, restore focus, set aria-hidden on achtergrond indien nodig.
  • Custom widgets: implementeer keyboard interactions (Enter/Space/Arrow keys) volgens WAI-ARIA Authoring Practices.
  • Valideer name, role, value (WCAG 4.1.2): test met accessibility tree.
  • Automatiseer checks met onze checker: wcagtool.nl/checker en installeer onze plugin via wcagtool.nl/plugin.

Tips voor designers en redacties

Design tokens voor focus

Definieer een focus-token in jullie design system zodat ontwikkelaars consistente focusstijlen gebruiken.

--focus-color: #005fcc;--focus-width: 3px;

Vermijd het weghalen van focus-rings

Als ontwerpers een andere visuele indicator willen, specificeer altijd een toegankelijke variant: kleurcontrast en grootte moeten voldoen aan zichtbaarheidseisen.

Voor redacties: maak interactieve tekst-links logisch en keyboard-vriendelijk

Links moeten duidelijk tekstueel zijn; vermijd “Klik hier”. Gebruik beschrijvende linktekst en zorg dat inline widgets (zoals accordions) met Enter/Space werken.

Hoe test je dit?

1. Keyboard-only test (manueel)

  1. Schakel muis uit of leg de muis weg.
  2. Plaats focus op de pagina en navigeer via Tab/Shift+Tab; check focusvolgorde en zichtbaarheid.
  3. Activeer interactieve elementen met Enter/Space en controleer gedrag (toggles, dropdowns, accordions, modals).

2. Screenreader & accessibility tree

  1. Open NVDA (Windows) of VoiceOver (macOS) en navigeer met de rotor/keyboard. Controleer roles, names en states.
  2. Inspecteer via browser devtools → Accessibility pane: controleer Name/Role/Value en hidden-attributes.

3. Automatische checks + onze WCAG checker

Gebruik een mix: automatische tools vangen technische fouten en missen context. Run onze checker op wcagtool.nl/checker en installeer de plugin via wcagtool.nl/plugin voor CI en lokale feedback.

4. Concrete testcases (copy-paste)

Voer deze scenario’s uit en noteer expected outcome:

  • Open een modal, Tab binnen modal en bevestig dat focus niet buiten komt. Expected: focus blijft in modal, Esc sluit modal en focus keert terug naar opener.
  • Keyboard-only: navigeer naar alle interactieve controls; Expected: alle controls bereikbaar en werkend met Enter/Space.
  • Custom widget: screenreader leest role en state (bijv. “aan/uit”). Expected: aria-pressed of aria-expanded is correct.

Snelle implementatie-templates

Accessible accordion (basis)

<div class="accordion">
  <h3><button aria-expanded="false" aria-controls="acc1">Section 1</button></h3>  
  <div id="acc1" hidden>Content 1</div></div>
// JS: toggle aria-expanded and hidden

Accessible dropdown (enter/space + arrow keys)

<div class="dropdown" role="listbox" tabindex="0" aria-activedescendant="">...</div>
// Implement arrow up/down to change aria-activedescendant and Enter to select

Checklist voor release / QA

  • Run keyboard-only check en documenteer uitzonderingen.
  • Voer screenreader-check uit op belangrijke workflows (inloggen, check-out, formulieren).
  • Automatiseer regressiechecks met onze plugin (wcagtool.nl/plugin).
  • Houd een duidelijke issues-lijst met reproducerende stappen en schermopnames.

Support & tooling

Test je werk direct met onze online WCAG checker: wcagtool.nl/checker. Voor integratie en CI gebruik onze plugin: wcagtool.nl/plugin. Heb je vragen? Vul het contactformulier in — we reageren binnen 24 uur en helpen met concrete code-aanpassingen.

Praktische tip: voeg tijdens ontwikkeling een CSS-klasse toe wanneer je toetsenbordgebruik detecteert, zodat je onderscheid kunt maken tussen mouse- en keyboard-focus en ontwerpers consequente focusstijlen kunnen laten zien.

// Simple keyboard-detection to toggle .js-focus on documentElement
function enableKeyboardFocus() {
  function handleFirstTab(e) {
    if (e.key === 'Tab') {
      document.documentElement.classList.add('js-focus');
      window.removeEventListener('keydown', handleFirstTab);
    }
  }
  window.addEventListener('keydown', handleFirstTab);
}
enableKeyboardFocus();

Previous Post Next Post

Geef een reactie

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