WCAG praktisch toepassen: direct werkbare oplossingen
Veel projecten missen toegankelijkheid omdat oplossingen theoretisch blijven, componenten onjuist ge-aria’d zijn, of keyboard- en focusgedrag niet getest wordt. Wij vertalen WCAG naar concrete code, testbare patronen en repeatable checklists zodat teams meteen kunnen implementeren en valideren.
Op wcagtool.nl richten we ons op praktische implementatie: duidelijke HTML/ARIA/CSS/JS-snippets, snelle checklists en integratie met onze WCAG checker en plugin. Test je site direct met onze validator, download de plugin voor je browser of neem contact op via ons contactformulier (antwoord binnen 24 uur).
Het probleem in de praktijk
Fout 1: Semantiek vervangen door styling
Veel teams gebruiken divs en spans in plaats van semantische elementen en voegen daarna ARIA toe om het goed te maken. ARIA mag helpen, maar vervangt geen correcte semantiek. Resultaat: screenreaders krijgen verwarrende of dubbele informatie.
Fout 2: Keyboard-interactie ontbreekt of is inconsistent
Custom controls (dropdowns, modals, tabs) missen focus management en keyboard handlers. Dat leidt tot onbruikbare UI voor toetsenbordgebruikers.
Fout 3: Geen focusstijl of focus outline weggepoetst
Designers verwijderen browserfocus en vergeten toegankelijke alternatieven. Zonder zichtbare focus verliest een gebruiker de context.
Zo los je dit op in code
Gebruik altijd semantische HTML
Basisregel: begin met het juiste element, voeg ARIA alleen toe om semantiek uit te breiden. Voorbeeld: gebruik <button> in plaats van <a href=”#”> of <div role=”button”> tenzij je een reden hebt.
<!-- correct: native button met duidelijke label --><br><button type="button" id="saveBtn">Opslaan</button>
Accessible custom button: ARIA + keyboard
Als je echt een custom element maakt, zorg dat role, tabindex en keyboard-events correct zijn.
<!-- custom element as button --><br><div role="button" tabindex="0" aria-pressed="false" id="customBtn">Opslaan</div><br><script>const btn = document.getElementById('customBtn');btn.addEventListener('click', ()=>{/* actie */});btn.addEventListener('keydown', (e)=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();btn.click();}});</script>
Focus management voor modals
Zorg dat focus naar de modal gaat, tab-loop binnen modal blijft en focus teruggaat naar trigger bij sluiten.
<!-- modal: focus trap minimal --><br><div id="modal" role="dialog" aria-modal="true" aria-labelledby="modalTitle" hidden><br><h2 id="modalTitle">Titel</h2><br><button id="closeModal">Sluit</button><br></div><br><script>const modal=document.getElementById('modal');const openBtn=document.getElementById('openModal');const closeBtn=document.getElementById('closeModal');openBtn.addEventListener('click', ()=>{modal.hidden=false;const focusable=[...modal.querySelectorAll('a,button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"])')];focusable[0].focus();document.addEventListener('keydown', trap);});function trap(e){if(e.key==='Tab'){const focusable=[...modal.querySelectorAll('a,button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"])')];const first=focusable[0];const last=focusable[focusable.length-1];if(e.shiftKey&&document.activeElement===first){e.preventDefault();last.focus();}else if(!e.shiftKey&&document.activeElement===last){e.preventDefault();first.focus();}}if(e.key==='Escape'){closeModal();}}function closeModal(){modal.hidden=true;document.removeEventListener('keydown', trap);openBtn.focus();}</script>
Contrast en visuele focus: CSS snippets
Voorkom verwijderen van outline. Gebruik aangepaste focus-styles die voldoen aan contrastregels.
/* zichtbare focus met voldoende contrast */:focus{outline:3px solid #005A9C;outline-offset:2px;box-shadow:0 0 0 3px rgba(0,90,156,0.15);}
Afbeeldingen en alt-teksten
Alt moet betekenis geven. Decoratieve afbeeldingen: alt=\”\” en aria-hidden indien nodig.
<img src=\"grafiek.png\" alt=\"Omzetstijging van 10% tussen 2023 en 2024\"><br><!-- decoratief --><br><img src=\"lijn.png\" alt=\"\" aria-hidden=\"true\">
Formulieren: labels, errors en aria-live
Koppel altijd label aan input via for/id of wrapping. Toon foutmelding met aria-invalid en aria-describedby, en zet updates in een live region.
<label for=\"email\">E-mail</label><br><input id=\"email\" name=\"email\" type=\"email\" aria-describedby=\"emailHelp emailError\"><br><div id=\"emailError\" role=\"alert\" aria-live=\"assertive\"></div>
Checklist voor developers
- Semantische elementen gebruiken: header, nav, main, footer, button, form, fieldset, legend.
- Geen keyboard traps: test Tab/Shift+Tab volledig.
- Focus zichtbaar en meetbaar contrast (>3:1 voor UI components, >4.5:1 voor tekst normaal).
- ARIA alleen ter aanvulling, niet ter vervanging van semantiek.
- Alt-teksten: beschrijvend of leeg voor decoratie.
- Formuliervalidatie: aria-invalid + aria-describedby + role=alert voor fouten.
- Modals & dialogs: aria-modal, focus trap, restore focus on close.
- Gebruik native controls waar mogelijk (select, button, input type=range).
Tips voor designers en redacties
Design tokens & contrast
Maak contrast-check onderdeel van design tokens. Exporteer kleuren en run contrast-tests automatisch in CI met onze validator of tools zoals axe-core.
Guidelines voor component library
Documenteer per component: semantic markup, keyboard flows, ARIA attributes, expected focus order en test-cases. Voorbeeld in component docs:
Button component behavior: <br>• Element: <button> <br>• Focus: default outline, custom state for pressed/disabled <br>• Keyboard: Enter and Space to activate <br>• Accessibility: aria-pressed for toggle buttons
Redactietips voor content-editors
Forseer alt-tekst in CMS, voorkom inline afbeeldingen zonder beschrijving, gebruik kopstructuren (H1..H6) sequentieel en voeg transcripties bij audio/video. Gebruik onze checklist in de CMS-workflow en test pagina’s met de wcagtool.nl checker voor publicatie.
Hoe test je dit?
Handmatige basischecks (quick wins)
- Keyboard-only navigatie: Tab, Shift+Tab, Enter, Space, Escape. Noteer traps en focusverlies.
- Screenreader test: NVDA (Windows) of VoiceOver (macOS). Luister naar volgorde en labels.
- Contrast check: gebruik onze WCAG checker of een contrast-app. Controleer tekst, iconen en focus-ringen.
Automated tests (CI)
Integreer axe-core of pa11y in je pipeline; gebruik onze WCAG validator voor een extra laag. Voorbeeld npm script met axe-core:
// voeg toe aan je test-suite (puppeteer + axe) <br>const { AxePuppeteer } = require('axe-puppeteer');(async ()=>{await page.goto('https://jouwsite.test');const results = await new AxePuppeteer(page).analyze();console.log(results.violations);})();
End-to-end testcases
Maak specifieke E2E tests die keyboard flows en focus-restoration controleren. Voorbeeld met Playwright:
// Playwright voorbeeld: focus restore test <br>await page.click('#openModal');await expect(page.locator('#modal')).toBeVisible();await page.keyboard.press('Escape');await expect(page.locator('#modal')).toBeHidden();await expect(page.locator('#openModal')).toBeFocused();
Snelcheck: gebruik onze WCAG checker
Voer je pagina direct door onze online WCAG checker op https://wcagtool.nl/checker. Voor continue feedback: installeer de plugin (https://wcagtool.nl/plugin-download) en test tijdens development. Vragen? Gebruik ons contactformulier: https://wcagtool.nl/contact (antwoord binnen 24 uur).
Concrete mini-how-to’s
Skip link implementatie
Skip links verbeteren keyboard en screenreader bereikbaarheid voor langere pagina’s.
<a href=\"#maincontent\" class=\"skip-link\">Direct naar hoofdinhoud</a><br><!-- CSS --><br>.skip-link{position:absolute;left:-999px;top:auto;width:1px;height:1px;overflow:hidden;} .skip-link:focus{position:static;left:0;width:auto;height:auto;}
Accessible tabs (ARIA + keyboard)
<div role=\"tablist\" aria-label=\"Voorbeeld tabs\"><br><button role=\"tab\" aria-selected=\"true\" aria-controls=\"panel1\" id=\"tab1\">Tab 1</button><br><button role=\"tab\" aria-selected=\"false\" aria-controls=\"panel2\" id=\"tab2\">Tab 2</button><br><div id=\"panel1\" role=\"tabpanel\" aria-labelledby=\"tab1\">Inhoud 1</div><br><div id=\"panel2\" role=\"tabpanel\" aria-labelledby=\"tab2\" hidden>Inhoud 2</div><br><script>const tabs=[...document.querySelectorAll('[role=tab]')];tabs.forEach(tab=>tab.addEventListener('keydown', e=>{const idx=tabs.indexOf(e.currentTarget);if(e.key==='ArrowRight'){tabs[(idx+1)%tabs.length].focus();}else if(e.key==='ArrowLeft'){tabs[(idx-1+tabs.length)%tabs.length].focus();}}));tabs.forEach(tab=>tab.addEventListener('click', e=>{tabs.forEach(t=>t.setAttribute('aria-selected','false'));e.currentTarget.setAttribute('aria-selected','true');document.querySelectorAll('[role=tabpanel]').forEach(p=>p.hidden=true);document.getElementById(e.currentTarget.getAttribute('aria-controls')).hidden=false;}));</script>
Checklist voor oplevering (gebruik in PR pipeline)
- Automated run: axe/pa11y + onze WCAG checker (https://wcagtool.nl/checker).
- Handmatige run: keyboard only, screenreader run (NVDA/VoiceOver), contrast check.
- Component docs bevatten accessibility section en testcases.
- CMS: verplichte alt-velden en semantische koppen afdwingen.
- Release checklist: valideer modals, dialogs, focus restore, form errors en live regions.
Laatste praktische tip
Voeg dit kleine script toe aan je CI of pre-commit om snel regressies te vangen — het runt onze publieke API van de WCAG checker en faalt bij ernstige issues. Voorbeeld:
// Node.js voorbeeld: call onze checker API <br>const fetch = require('node-fetch');(async ()=>{const url='https://wcagtool.nl/api/check?url=https://jouwsite.test';const res=await fetch(url);const data=await res.json();if(data.violations && data.violations.length>0){console.error('Accessibility violations found', data.violations);process.exit(1);}console.log('No blocking accessibility issues');})();
Test je pagina nu met onze WCAG checker: https://wcagtool.nl/checker. Download de plugin: https://wcagtool.nl/plugin-download. Vragen? Gebruik https://wcagtool.nl/contact — wij reageren binnen 24 uur.