Dynamische content en WCAG: tips voor developers

Toegankelijkheid: Keyboard en focusmanagement praktisch toepassen — WCAGtool

Keyboard-toegankelijkheid en correct focusmanagement falen in 70% van de praktijkimplementaties: skip-links vergeten, tabindex verkeerd gebruikt, modals zonder focus trap en custom controls zonder ARIA/keyboard support. Dat veroorzaakt onbereikbare content voor toetsenbordgebruikers en screen-reader gebruikers.

Wij vertalen WCAG-criteria naar concrete, testbare code en checklists die je direct in je projecten plakt. Gebruik onze voorbeelden, teststappen en de WCAG checker op https://wcagtool.nl om je site direct te valideren. Download ook onze plugin op https://wcagtool.nl/plugin of vraag hulp via het contactformulier; we beantwoorden vragen binnen 24 uur.

Het probleem in de praktijk

Veelvoorkomende fouten

  • Geen skip-link of onzichtbare skip-link die niet focusbaar is.
  • Tabindex misbruikt (tabindex=”0″ vs tabindex=”-1″ verkeerd geplaatst).
  • Custom controls (divs/spans) zonder keyboard handlers en ARIA.
  • Modals en dialogs zonder focus trap en zonder terugzetten van focus bij sluiten.
  • Gebruik van :focus zonder :focus-visible waardoor visuele indicatoren inconsistent zijn.

Impact op gebruikers

Toetsenbordgebruikers kunnen niet navigeren of raken ‘vast’ in interactieve componenten; screen-readergebruikers verliezen context zonder juiste ARIA-live/roledocumentatie; en toetsenbord-only gebruikers missen visuele focus-indicatoren.

Zo los je dit op in code

Skip-link die direct werkt

Voeg een skip-link toe die zichtbaar wordt op focus. Testbaar en eenvoudig:

<a class="skip-link" href="#main">Skips naar hoofdcontent</a><br><!-- Plaats direct na <body> -->
/* CSS */
.skip-link{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden;}
.skip-link:focus{position:static;left:auto;width:auto;height:auto;padding:8px;background:#000;color:#fff;z-index:1000;}

Correct gebruik van tabindex

Regel: gebruik zoveel mogelijk semantische elementen (<button>, <a>, <input>). Gebruik tabindex=”0″ om een element in tabvolgorde te brengen, tabindex=”-1″ om focus programmatisch toe te wijzen.

<!-- Slecht: clickable div -->
<div onclick="doSomething()">Click me</div>
<!-- Beter: semantisch -->
<button type="button" onclick="doSomething()">Click me</button>

Focus-visible: toon alleen bij keyboard

/* CSS */
:focus{outline:none;}
:focus-visible{outline:3px solid #0066cc;outline-offset:2px;}

Voor browsers zonder :focus-visible: voeg een polyfill of JS-fallback toe die class “user-is-tabbing” op <body> zet (voorbeeld hieronder).

Accessible custom control (dropdown) — HTML + ARIA + keyboard

<div class="dropdown" role="combobox" aria-expanded="false" aria-haspopup="listbox">
<button class="dropdown-toggle" aria-controls="dl" aria-expanded="false">Kies optie</button>
<ul id="dl" role="listbox" tabindex="-1" hidden>
<li role="option" tabindex="-1">Optie 1</li>
<li role="option" tabindex="-1">Optie 2</li>
</ul>
</div>
// JS: open/close + keyboard handlers (vereenvoudigd)
document.querySelector('.dropdown-toggle').addEventListener('click', function(e){
const dl = document.getElementById('dl');
const expanded = this.getAttribute('aria-expanded') === 'true';
this.setAttribute('aria-expanded', String(!expanded));
dl.hidden = expanded;
if(!expanded){ dl.querySelector('[role=\"option\"]').focus(); }
});
document.querySelectorAll('[role=\"option\"]').forEach((opt)=>{
opt.addEventListener('keydown', function(e){
if(e.key==='ArrowDown'){ e.preventDefault(); this.nextElementSibling?.focus(); }
if(e.key==='ArrowUp'){ e.preventDefault(); this.previousElementSibling?.focus(); }
if(e.key==='Enter'){ this.click(); }
if(e.key==='Escape'){ this.closest('[role=\"listbox\"]').hidden = true; document.querySelector('.dropdown-toggle').focus(); }
});
});

Modal met focus trap en restore focus

<button id="openModal">Open Modal</button>
<div id="modal" role="dialog" aria-modal="true" aria-hidden="true" tabindex="-1">
<button id="closeModal">Sluit</button>
<a href="#">Link in modal</a>
</div>
// JS: simpele focus trap & restore
const openBtn = document.getElementById('openModal');
const modal = document.getElementById('modal');
const closeBtn = document.getElementById('closeModal');
let lastFocused;
openBtn.addEventListener('click', ()=>{
lastFocused = document.activeElement;
modal.removeAttribute('aria-hidden'); modal.focus();
document.addEventListener('focus', trapFocus, true);
});
closeBtn.addEventListener('click', ()=>{
modal.setAttribute('aria-hidden', 'true');
document.removeEventListener('focus', trapFocus, true);
lastFocused?.focus();
});
function trapFocus(e){
if(!modal.contains(e.target)){ e.stopPropagation(); modal.focus(); }
}

Checklist voor developers

  • Gebruik semantische HTML (buttons, links, form elements) in plaats van div/span voor interactieve items.
  • Voeg skip-links toe en maak ze zichtbaar bij focus.
  • Gebruik :focus-visible voor focusstijl; voeg polyfill of JS fallback toe waar nodig.
  • Gebruik tabindex=”-1″ voor programmatische focus, tabindex=”0″ om in taborder te brengen. Vermijd positieve tabindex-waarden.
  • Voeg ARIA-roles, states en properties toe waar native semantics ontbreken (role=”dialog”, aria-modal, aria-expanded, aria-controls, role=”option” etc.).
  • Zorg dat modals focus trap implementeren en focus restore bij sluiten.
  • Implementeer keyboard-navigatie voor custom widgets (Arrow keys, Home/End, Enter/Escape).
  • Test op echte toetsenbordnavigatie en screenreaders; automatiseer met onze WCAG checker.

Tips voor designers en redacties

Designers: focus zichtbaar en consistente patronen

  • Ontwerp duidelijke focusstaten (contrast, breedte, offset). Gebruik :focus-visible in component CSS.
  • Maak componentbibliotheken met toegankelijke patterns (modals, dropdowns, datagrids) en documenteer keyboard flows.

Redacties: content en tabvolgorde

  • Zorg dat content logisch in de DOM staat; visuele layout mag niet de tabvolgorde bepalen.
  • Gebruik duidelijke linkteksten (geen “klik hier”) en structureer headings semantisch.

Wil je voorbeelden voor je designsystem? Gebruik onze plugin (https://wcagtool.nl/plugin) om componenten te scannen en ontvang concrete fixes.

Hoe test je dit?

Handmatige toetsenbordtests (direct toepassen)

  1. Open je pagina zonder muis. Druk op Tab om door interactieve elementen te navigeren — alles interageerbaars moet bereikbaar zijn en focus zichtbaar.
  2. Gebruik Shift+Tab om terug te gaan. Controleer of focus niet “verloren” gaat of vastzit.
  3. Open modals/drawers en controleer focus trap (tab blijft binnen modal) en dat focus terugkeert naar het element dat de modal opende bij sluiten.
  4. Test custom widgets: Arrow keys, Enter, Space, Escape, Home/End werken conform verwachting.

Automatische en semi-automatische tooling

  • Draai onze WCAG checker op https://wcagtool.nl voor gerichte issues en bijbehorende code-fixes.
  • Gebruik browser devtools Accessibility pane en de tab-order overlay.
  • Gebruik een screenreader (NVDA/VoiceOver) en navigeer met headings en links.

Snelle testcases (copy/paste)

// Test 1: Skip link
Plak de skip-link code in de top van je pagina, refresh, druk Tab. Werkt de link?
// Test 2: Modal
Plak de modal code; open modal; probeer Tab en Shift+Tab om te controleren of focus binnen blijft en terugkeert.

Tip: Start altijd met de “keystone” checks in onze validator: skip-link, focus-visible en tabindex regels. Test je site direct met onze WCAG checker op https://wcagtool.nl — snelle scan, concrete fix-voorstellen.

Download onze plugin (https://wcagtool.nl/plugin) om fouten direct in je componenten te vinden en stuur vragen via https://wcagtool.nl/contact (antwoord binnen 24 uur). Als laatste praktische check: plak dit korte script in je console om interactieve elementen zonder focus te vinden:

// Voer in console: vind elementen met onclick zonder tabindex of role
Array.from(document.querySelectorAll('[onclick], [role=\"button\"], [role=\"link\"]')).filter(el => !el.matches('a,button,input,select,textarea') && getComputedStyle(el).pointerEvents !== 'none').slice(0,50)

Voer nu een scan met onze WCAG checker op https://wcagtool.nl en download de plugin op https://wcagtool.nl/plugin om direct te starten met fixes.