Veel teams missen in de praktijk de aansluiting tussen WCAG-vereisten en werkende code: goede intenties, maar ontbrekende focusbeheer, verkeerde ARIA-toepassingen en ongeteste kleurcontrastregels zorgen voor ontoegankelijke ervaringen. Wij vertalen WCAG naar concrete, testbare stappen die developers, frontend engineers, designers en redacties direct kunnen toepassen.
Dit artikel geeft concrete oplossingen met stap-voor-stap instructies, kant-en-klare code-snippets en testscenario’s. Gebruik onze WCAG checker om je implementatie direct te valideren, download onze plugin voor CI-integratie of stuur vragen via het contactformulier — we beantwoorden binnen 24 uur.
Het probleem in de praktijk
Veelvoorkomende fouten
1) Geen keyboard-focus of focus traps. 2) Visuele focus niet zichtbaar (of weggefilterd). 3) Onjuiste of overbodige ARIA-attributen. 4) Formulieren zonder labels/inline errors. 5) Slecht contrast of kleur als enige onderscheid. Elk van deze fouten veroorzaakt directe toegankelijkheidsproblemen voor schermlezers en toetsenbordgebruikers.
Waarom dit vaak misgaat
Teams behandelen toegankelijkheid als checklist in plaats van runtime-eigenschap: zonder component-level patterns en testcases ontstaan regressies. Wij leveren patterns, code en teststappen die je CI en design-systeem kunt opnemen.
Zo los je dit op in code
1. Skip link (voor keyboard- en screenreadergebruikers)
<a href="#main-content" class="skip-link">Sla navigatie over</a><!-- Plaats als eerste element --><main id="main-content">...content...</main>
2. Focus management en focus-visible
Gebruik CSS :focus-visible en zet focus programatisch na dialogs of navigation.
/* CSS */:focus-visible{outline:3px solid #005fcc;outline-offset:2px}button:focus{box-shadow:0 0 0 3px rgba(0,95,204,.2)}
// JavaScript: zet focus naar dialog title after open
const dialog = document.querySelector('#dialog');
const dialogTitle = dialog.querySelector('.dialog__title');
function openDialog(){dialog.setAttribute('open','');dialogTitle.focus();}
3. Knoppen vs links: semantics kloppen
Gebruik <button> voor acties, <a> voor navigatie. Vervang niet met role-atributen tenzij semantiek onmogelijk is.
<!-- Correct: actie --><button type="button" class="save">Opslaan</button><!-- Correct: navigatie --><a href="/download" class="download">Download</a>
4. Formulieren: labels en inline errors
<label for="email">E-mail</label><input id="email" name="email" type="email" aria-describedby="email-error" required><div id="email-error" role="alert" aria-live="assertive"><!-- gevuld via JS bij fout --></div>
// JS validatie: geef error en focus
const input = document.getElementById('email');
const err = document.getElementById('email-error');
function validateEmail(){if(!input.value.includes('@')){err.textContent='Vul een geldig e-mailadres in';input.setAttribute('aria-invalid','true');input.focus();}else{err.textContent='';input.removeAttribute('aria-invalid');}}
5. ARIA: gebruik spaarzaam en correct
Voorkom aria-attributes als ze niet nodig zijn. Gebruik role=”alert” voor systeemmeldingen en aria-live voor dynamische content.
<div role="status" aria-live="polite">Opslaan voltooid</div>
6. Contrast: variabelen en checks
/* CSS variabelen */:root{--text:#1a1a1a;--bg:#ffffff}body{color:var(--text);background:var(--bg)}
// JavaScript contrast check (voor component testen)
function luminance(r,g,b){const a=[r,g,b].map(v=>{v/=255;return v<=0.03928?v/12.92:Math.pow((v+0.055)/1.055,2.4)});return 0.2126*a[0]+0.7152*a[1]+0.0722*a[2]}
function contrast(hex1,hex2){const toRgb=h=>h.replace('#','').match(/.{2}/g).map(x=>parseInt(x,16));const L1=luminance(...toRgb(hex1));const L2=luminance(...toRgb(hex2));const lighter=Math.max(L1,L2);const darker=Math.min(L1,L2);return (lighter+0.05)/(darker+0.05)}
console.log('Contrast',contrast('#1a1a1a','#ffffff'));
7. Focus traps vermijden (modals)
// Eenvoudige focus trap opener/closer
function trapFocus(container){const focusable='a[href],button,textarea,input,select,[tabindex]:not([tabindex="-1"])';const nodes=Array.from(container.querySelectorAll(focusable));const first=nodes[0],last=nodes[nodes.length-1];
container.addEventListener('keydown',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();}});}
Checklist voor developers
- Semantische HTML eerst: headings, buttons, lists.
- Keyboard: test volledige flow met Tab/Shift+Tab, Enter, Space, Escape.
- Focus zichtbaar: gebruik :focus-visible en test met browser-instellingen.
- Forms: labels, aria-describedby voor fouten, role=”alert” voor meldingen.
- Color contrast >= 4.5:1 voor body tekst; 3:1 voor grote tekst.
- ARIA alleen als extra semantiek vereist is — documenteer patronen.
- Voeg e2e tests toe die accessibility-gevallen simuleren (keyboard, screenreader attributes).
Tips voor designers en redacties
Design tokens en kleurkeuze
Definieer kleuren als CSS-variabelen per token en documenteer contrastratio’s in het design-systeem. Voorbeeld:
:root{--primary:#005fcc;--text:#1a1a1a;--muted:#6b6b6b}
Labelling en content-strategie
Schrijf korte, duidelijke link- en knopteksten (geen “Klik hier”). Maak foutmeldingen actiegericht: wat is fout en welke stap volgt.
Design review checklist
Controleer: focus states, contrast, no reliance on color only, aria-usage. Gebruik onze WCAG checker tijdens design reviews.
Hoe test je dit?
1. Handmatige tests (stap-voor-stap)
- Keyboard-only: Navigeer volledig met Tab/Shift+Tab, activeer alle controls en sluit modals met Escape.
- Screenreader: test met NVDA/VoiceOver — controleer order en leesbare labels.
- Contrast: controleer met onze checker of browser-extensies en de ingebouwde contrastfunctie in design tools.
2. Automatische en CI-tests
Integreer axe-core/pa11y in je pipeline en voeg component-level accessibility tests toe. Run onze WCAG checker als stap in CI of gebruik onze plugin voor snelle rapportage.
// Voorbeeld: npm script met pa11y
"scripts":{ "a11y":"pa11y http://localhost:3000 --reporter html > a11y-report.html" }
3. Gebruikerstests
Laat echte gebruikers met een handicap een korte taak uitvoeren en meet tijd en fouten. Combineer met analytics voor drop-off points.
4. Onze tools
Test je live site direct: <a href=”https://wcagtool.nl/checker” target=”_blank”>WCAG checker/validator</a>. Download onze plugin voor VS Code en CI: <a href=”https://wcagtool.nl/plugin” target=”_blank”>Plugin downloaden</a>. Vragen? Gebruik ons <a href=”https://wcagtool.nl/contact” target=”_blank”>contactformulier</a> — antwoord binnen 24 uur.
Praktische mini-how-to’s
Accessible button component (React)
import React from 'react';
export default function Button({children,onClick,disabled}){return (<button type="button" onClick={onClick} disabled={disabled} className="btn">{children}</button>);}
Accessible input component met ARIA-fallback
function TextInput({id,label,value,onChange,error}){return (<div><label htmlFor={id}>{label}</label><input id={id} value={value} onChange={onChange} aria-describedby={error?`${id}-error`:undefined} aria-invalid={error?true:false}/>{error?<div id={`${id}-error`} role="alert">{error}</div>:null}</div>)}
Contrast-check script voor componenten
// Gebruik dit in storybook tests of unit-tests
import {contrast} from './contrast';
test('primary text contrast',()=>{expect(contrast('#1a1a1a','#ffffff')).toBeGreaterThan(4.5)});
Extra checklists en quick-fixes
- Voeg skip link toe als eerste element.
- Zorg dat modals focus terugzetten naar opener.
- Vervang div-knoppen door echte button-elementen.
- Documenteer ARIA-only exceptions in component docs.
- Automatiseer met onze checker & plugin in CI.
Test nu direct: <a href=”https://wcagtool.nl/checker” target=”_blank”>run de WCAG checker</a>, <a href=”https://wcagtool.nl/plugin” target=”_blank”>download de plugin</a> of stuur ons een vraag via het <a href=”https://wcagtool.nl/contact” target=”_blank”>contactformulier</a> (antwoord binnen 24 uur).
Laatste praktische tip: voeg deze korte smoke-test toe aan je deployment pipeline — draait deze, dan zijn de grootste regressies direct zichtbaar:
# CI step (bash)
curl -s https://wcagtool.nl/checker?url=$DEPLOY_URL | grep -q '"violations":0' || { echo "Accessibility issues found"; exit 1; }