WCAG en e-commerce: toegankelijk shoppen online

Toegankelijke toetsenbordnavigatie en focusbeheer — Praktische implementatie | wcagtool.nl

Toegankelijke toetsenbordnavigatie en focusbeheer

Toetsenbordnavigatie en focusbeheer zijn in de praktijk vaak fout uitgevoerd: skip-links ontbreken of worden onzichtbaar gemaakt, modals slopen focus, SPA-route-wissels verplaatsen geen focus en custom components missen ARIA en tabindex-logica. Resultaat: keyboard-only gebruikers en schermlezers lopen vast.

Wij bieden concrete, testbare oplossingen: stap-voor-stap codevoorbeelden voor HTML/ARIA/CSS/JS, checklisten voor developers en praktische instructies voor designers en redacties. Test direct met onze WCAG checker, download onze plugin via wcagtool.nl/plugin en vraag hulp via het contactformulier (vragen worden binnen 24 uur beantwoord).

Het probleem in de praktijk

Veelvoorkomende fouten

  • Geen skip-link of skip-link die pas zichtbaar wordt ná focus, of die geen focus-ontoegankelijk element target.
  • Custom controls zonder tabindex of ARIA waardoor niet bereikbaar met toetsenbord.
  • Modals en dialogs zetten focus niet correct, of laten focus ontsnappen (geen focus-trap).
  • SPA navigatie verandert URL maar verplaatst geen focus naar begin van de content.
  • Onzichtbare maar focusbare elementen of visuele outlines worden verwijderd zonder alternatief.

Waarom dat kritisch is

WCAG-eisen zoals 2.1.1 (Keyboard), 2.4.3 (Focus Order), 2.4.7 (Visible Focus) en 4.1.2 (Name, Role, Value) worden vaak verbroken. Dit betekent slechtere gebruikservaring en juridische risico’s. Praktische implementatie voorkomt dat.

Zo los je dit op in code

1) Skip-link: standaard en zichtbaar bij focus

Implementatie: voeg een skip-link bovenaan je page, maak hem visueel verborgen maar zichtbaar bij :focus. Test: Tab als eerste element en controleer zichtbaarheid.

<a class="skip-link" href="#main">Sla navigatie over</a><br><!-- CSS --><br>.skip-link{position:absolute;left:-9999px;top:auto;width:1px;height:1px;overflow:hidden}<br>.skip-link:focus{position:static;left:auto;top:auto;width:auto;height:auto;padding:0.5rem;background:#005a9c;color:#fff;z-index:1000}

2) Focus-visible en outline: behoud zichtbare focus

Gebruik :focus-visible om geen false negatives te creëren en behoud outline voor keyboardgebruikers.

/* CSS */<br>:focus{outline:none}<br>:focus-visible{outline:3px solid #ffb84d;outline-offset:2px;border-radius:2px}

3) Accessible custom button / role=”button”

Als je een element opbouwt als knop, voeg de juiste ARIA, tabindex en keyboard handlers toe. Gebruik native <button> waar mogelijk.

<!-- HTML --><br><div role="button" tabindex="0" aria-pressed="false" id="likeBtn">Like</div><br><!-- JS --><br>document.getElementById('likeBtn').addEventListener('keydown', function(e){ if(e.key==='Enter' || e.key===' '){ e.preventDefault(); this.click(); } });

4) Modal / dialog: focus-trap en aria-modal

Stappen: 1) geef dialog role=”dialog” en aria-modal=”true”; 2) zet focus op eerste focusable element of op container met tabindex=”-1″; 3) implementeer focus-trap (tab, shift+tab) en sluit met Escape; 4) restore focus naar opener bij sluiten.

<!-- HTML --><br><div id="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" tabindex="-1" hidden><br><h2 id="modalTitle">Instellingen</h2><br><button id="closeModal">Sluiten</button><br></div><br><!-- JS (basis focus-trap) --><br>const modal=document.getElementById('modal'); const opener=document.getElementById('openModal'); opener.addEventListener('click', ()=>{ modal.hidden=false; modal.focus(); }); modal.addEventListener('keydown', e=>{ if(e.key==='Escape') closeModal(); if(e.key==='Tab'){ const focusables = modal.querySelectorAll('a[href],button,textarea,input,select,[tabindex]:not([tabindex=\"-1\"])'); const first = focusables[0]; const last = focusables[focusables.length-1]; if(e.shiftKey && document.activeElement===first){ e.preventDefault(); last.focus(); } else if(!e.shiftKey && document.activeElement===last){ e.preventDefault(); first.focus(); } } }); function closeModal(){ modal.hidden=true; opener.focus(); }

5) Single Page Applications: focus bij route-wissel

Stappen: na route change, verplaats focus naar een element met role=”main” of header van de content en geef het tabindex=”-1″ indien nodig.

// pseudo-code voor router hooks<br>router.on('routeChangeComplete', ()=>{ const main=document.querySelector('main'); if(main){ main.setAttribute('tabindex','-1'); main.focus(); // optioneel remove attribute na eerste focus } });

6) Verberg visueel maar niet voor AT: use aria-hidden correct

Als je content visueel verborgen maakt voor layout, zorg dat screen readers niet per ongeluk uitgesloten of dubbel voorgelicht worden. Gebruik aria-hidden en inert/hidden zorgvuldig.

<!-- correct: visueel verbergen voor AT --><br><div aria-hidden="false">Zichtbaar voor screenreaders</div><br><!-- verbergen voor AT --><br><div aria-hidden="true">Verborgen voor screenreaders</div>

Checklist voor developers

  • Is een skip-link aanwezig en focusable?
  • Heeft elk interactief element een semantische tag of role + tabindex?
  • Behoud je focus-outline of gebruik je :focus-visible correct?
  • Gebruiken modals role=”dialog”, aria-modal en een focus-trap?
  • Restore focus naar opener na sluiten dialog/modal?
  • Wisselt focus correct na SPA-route changes?
  • Test met keyboard-only, schermlezer en onze WCAG checker?

Tips voor designers en redacties

Design tokens en focus-states

Wireframe en definieer focus-states in het component library. Gebruik contrast- en zichtbaarheidstoetsen: focus-outline moet voldoen aan kleurcontrastregels.

Content-editing: geen interactieve content in headings

Moedig redacteurs aan om geen interactieve elementen te plaatsen in koppen zonder voldoende ARIA en tabindex; geef templates met correct gebruikte <button> en links.

Component library regels

  • Altijd native elementen gebruiken waar mogelijk (<button>, <a>).
  • Documenteer ARIA, keyboard flows en expected focus order per component.
  • Automatiseer tests in CI met onze plugin voor component libraries.

Hoe test je dit?

Handmatige tests (snel en effectief)

  1. Keyboard-only navigatie: tab door pagina, zorg dat alle interactieve items bereikbaar en logisch zijn.
  2. Focus order: gebruik Shift+Tab en Tab om te controleren of volgorde logisch is.
  3. Modals: open modal, probeer alles met Tab en Escape, en sluit modal; focus moet terug naar opener.
  4. Skip-link: Tab als eerste element en activeer skip-link; content moet meteen focus krijgen.

Automated checks en our tools

Gebruik onze WCAG checker voor geautomatiseerde scans (inclusief keyboard checks en missing ARIA). Installeer de wcagtool plugin in je CI/CD pipeline voor regressietests. Vragen? Gebruik het contactformulier — we reageren binnen 24 uur.

Screenreader tests

Test met NVDA/JAWS (Windows) en VoiceOver (macOS/iOS). Controleer dat labels, rollen en statusinformatie (aria-live) correct en niet dubbel wordt voorgelezen.

Browser devtools

Gebruik Accessibility pane (Chrome/Edge) om accessibility tree te inspecteren: check role, name, focusable, aria-hidden en tabindex.

Praktische mini-how-to’s

Quick-fix: maak alle custom controls keyboard-accessible

// Voor elk custom control: voeg attribuut en keydown handler toe<br>el.setAttribute('role','button'); el.setAttribute('tabindex','0'); el.addEventListener('keydown', e => { if(e.key==='Enter' || e.key===' ') { e.preventDefault(); el.click(); } });

Mini-script: restore focus na AJAX content load

// Plaats dit in je fetch callback<br>fetch('/page/section').then(r=>r.text()).then(html=>{ main.innerHTML=html; main.setAttribute('tabindex','-1'); main.focus(); // verwijder tabindex daarna main.removeAttribute('tabindex'); });

Verifiëren met onze checker via CLI (voorbeeld)

// gebruik onze plugin/CLI indien beschikbaar (voorbeeld) <br>npm run wcagtool -- --url=https://jouwsite.nl

Extra checklists en foutopsporing

Als focus- outline toch weg is

  • Controleer CSS: zoek naar outline:none global rules.
  • Gebruik :focus-visible waar mogelijk.
  • Voeg fallback style toe voor oudere browsers.

Als modal niet focusable is

  • Controleer of container tabindex=”-1″ heeft.
  • Zet focus expliciet met element.focus() na tonen.
  • Controleer of aria-hidden op achtergrond niet interfereert.

Hoe wij je kunnen helpen

Laat ons je site scannen met de WCAG checker, installeer onze plugin voor CI-tests en vraag advies via het contactformulier. Reactietijd: binnen 24 uur. We leveren concrete code-patches, pull-request ready fixes en component-library updates.

Direct toepasbare tip: voeg dit korte CSS-fragment toe aan je globale stylesheet om meteen veel focus-problemen op te lossen:

/* Plak in globals.css */<br>:focus{outline:none}<br>:focus-visible{outline:3px solid #0078d4;outline-offset:2px}

Test nu direct je website met onze WCAG checker, download de plugin voor geautomatiseerde tests en neem contact op via het contactformulier voor specifieke implementatievragen (antwoord binnen 24 uur).