Wat is WCAG? De basis uitgelegd

WCAG praktisch: Concrete implementaties voor developers, designers en redacties — wcagtool.nl

WCAG praktisch toepassen: direct testbare oplossingen

In de praktijk falen implementaties vaak op kleine, technische details: ontbrekende focusmanagement, onjuiste ARIA-toepassing, slecht getagde formulieren en ongeteste dynamische updates. Dat zijn geen abstracte regels maar concrete fouten die gebruikers blokkeren.

Wij vertalen WCAG naar korte, stap-voor-stap oplossingen die je direct in code toepast en test. Gebruik onze WCAG checker/validator om je implementatie direct te scannen, download onze plugin voor CI-integratie en neem contact op via het contactformulier — vragen beantwoorden we binnen 24 uur.

Het probleem in de praktijk

1. Keyboard-navigatie faalt

Veel componenten missen logisch tabindex-gedrag, focus verdwijnt bij modals of dynamische content en focus-styles zijn verwijderd. Gevolg: toetsenbordgebruikers raken vast.

2. Onjuiste of overbodige ARIA

Ontwikkelaars gebruiken ARIA attributes zonder eerst semantische HTML te kiezen. Resultaat: screenreaders krijgen tegenstrijdige informatie.

3. Dynamische updates zijn niet voorgelezen

Content die via JS laadt of verandert krijgt geen aria-live of role=alert, dus screenreadergebruikers missen belangrijke updates.

4. Formulieren geven onduidelijke fouten

Errors hebben geen aria-describedby/aria-invalid, foutboodschappen worden niet gefocust en labels zijn niet gekoppeld.

Zo los je dit op in code

Skip-link: HTML + CSS

Voeg een skip-link toe, zichtbaar bij focus. Test: tab naar bovenkant pagina.

<a href="#maincontent" class="skip-link">Sla navigatie over</a><br><style>.skip-link{position:absolute;left:-999px;top:auto;height:1px;width:1px;overflow:hidden}.skip-link:focus{position:static;left:auto;top:auto;height:auto;width:auto;padding:8px;background:#000;color:#fff;z-index:1000}</style>

Accessible focus styles (CSS)

Gebruik :focus-visible en behoud duidelijke outlines.

/* keep custom but visible focus */button, a, input{outline:none}button:focus-visible, a:focus-visible, input:focus-visible{outline:3px solid #0a84ff;outline-offset:2px}

Semantische HTML eerst, ARIA alleen als nodig

Gebruik native elementen: <button> i.p.v. <div role="button">. ARIA mag alleen extra info toevoegen.

<!-- juist --><button type="button">Sluiten</button><br><!-- onjuist --><div role="button" tabindex="0">Sluiten</div>

Modal met focus trap (JavaScript, testable)

Stap 1: open modal en focus eerste focusable; stap 2: focus trap terugzetten; stap 3: restore focus naar opener.

/* minimaal focus-trap */const openBtn=document.querySelector('#open');const modal=document.querySelector('#modal');const closeBtn=modal.querySelector('.close');let lastFocus=null;function trap(e){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.key==='Tab'){if(e.shiftKey && document.activeElement===first){e.preventDefault();last.focus()}else if(!e.shiftKey && document.activeElement===last){e.preventDefault();first.focus()}}}openBtn.addEventListener('click',()=>{lastFocus=document.activeElement;modal.style.display='block';modal.setAttribute('aria-hidden','false');modal.querySelector('button, a, input').focus();document.addEventListener('keydown',trap)});closeBtn.addEventListener('click',()=>{modal.style.display='none';modal.setAttribute('aria-hidden','true');document.removeEventListener('keydown',trap);if(lastFocus)lastFocus.focus()});

ARIA live region voor dynamische updates

Gebruik role=alert of aria-live=polite afhankelijk van urgentie.

<div id="status" aria-live="polite" aria-atomic="true"></div><br>/* update via JS */document.getElementById('status').textContent='Opslaan voltooid';

Formuliervalidatie: label + error linkage

Voorzie veldsets en koppel errors via aria-describedby; zet aria-invalid bij fout.

<label for="email">E-mail</label><input id="email" name="email" type="email" aria-describedby="emailError"><div id="emailError" class="error" aria-live="assertive"></div><br>/* JS */const inp=document.getElementById('email');const err=document.getElementById('emailError');if(!/\S+@\S+\.\S+/.test(inp.value)){inp.setAttribute('aria-invalid','true');err.textContent='Voer een geldig e-mailadres in';err.focus()}else{inp.removeAttribute('aria-invalid');err.textContent=''};

Contrast: CSS-variabelen en tools

Gebruik kleuren via CSS-variabelen en check tegen WCAG AA/AAA. Voorbeeld variabele set en functie.

:root{--brand:#0a84ff;--text:#222}body{color:var(--text);background:#fff}/* test contrast met onze checker of automatisering in CI via wcagtool plugin */

Checklist voor developers

  • Semantische HTML eerst — pas ARIA alleen toe waar nodig.
  • Keyboard toegankelijkheid: every interactive element tabbable in juiste order.
  • Focus management: modals, dialogs, navigatie en error focus.
  • Visible focus: gebruik :focus-visible met duidelijke outlines.
  • Formulieren: label-for, aria-describedby voor errors, aria-invalid bij fout.
  • Dynamische updates: aria-live / role=alert waar relevant.
  • Contrast: meet kleuren en tekstgrootte tegen WCAG AA/AAA.
  • Automated tests: run onze WCAG checker/validator en integreer onze plugin in CI.

Tips voor designers en redacties

Design tokens en kleurbeheer

Leg kleurvarianten als design tokens vast en definieer fallback-varianten met voldoende contrast. Voorbeeld JSON token:

{"color-primary":"#0a84ff","color-primary-contrast":"#ffffff"}

Titel- en kopstructuur

Gebruik H1..H6 semantisch per pagina; een logische, hiërarchische structuur helpt screenreadergebruikers en SEO.

Redactionele richtlijnen voor linktekst

Linktekst moet context bieden buiten de zin: vermijd ‘klik hier’. Voorbeeld: ‘Lees meer over toegankelijk schrijven’.

Media: captions en transcripts

Voor audio/video altijd ondertitels en transcript aanbieden, plaats link direct bij media en test met screenreader.

Hoe test je dit?

Handmatige testen (essentieel)

1) Alleen toetsenbord: tab door de site, controleer zichtbare focus en tabbable order. 2) Screenreader: NVDA/VoiceOver elke nieuwe feature doorlopen. 3) Contrast check: gebruik onze kleurchecker en meet varianten.

Automatische tools

Gebruik onze WCAG checker/validator (https://wcagtool.nl/validator) voor snelle scans. Integreer de plugin via npm in CI zodat PRs automatisch gecontroleerd worden (download op https://wcagtool.nl/plugin).

Axe-core quickscan (voorbeeld)

/* run in browser console */(async ()=>{const script=document.createElement('script');script.src='https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.8.0/axe.min.js';document.head.appendChild(script);script.onload=async ()=>{const results=await axe.run();console.log(results);};})();

CI integratie (npm)

npm install --save-dev wcagtool-plugin <br>// package.json script "test:accessibility":"wcagtool run --url https://staging.example.com"

Concrete mini-how-to’s (h3’s voor snelle copy/paste)

Toggle aria-expanded (voorbeeld code)

<button id="menuBtn" aria-expanded="false" aria-controls="menu">Menu</button><nav id="menu" hidden>...</nav><br>document.getElementById('menuBtn').addEventListener('click',function(){const open=this.getAttribute('aria-expanded')==='true';this.setAttribute('aria-expanded',String(!open));document.getElementById('menu').hidden=open});

Role alert met debounce (vermijd spam)

function announce(msg){const el=document.getElementById('srStatus')||Object.assign(document.createElement('div'),{id:'srStatus',style:'position:absolute;left:-9999px'});el.setAttribute('aria-live','assertive');el.setAttribute('aria-atomic','true');el.textContent=msg;document.body.appendChild(el)}let timer;function announceDebounced(msg){clearTimeout(timer);timer=setTimeout(()=>announce(msg),100)}

Testing checklist (copy/paste voor testscript)

1. Tab through all interactive items (no traps).2. Open modal: focus in modal, tab stays inside, close returns focus.3. Submit invalid form: field gets aria-invalid and error is focused.4. Dynamic messages announced via aria-live.5. Colors pass contrast checks (AA / AAA where required).6. Run wcagtool validator: https://wcagtool.nl/validator

Call-to-action en ondersteuning

Scan je pagina direct met onze WCAG checker/validator: https://wcagtool.nl/validator. Download de plugin voor CI en ontwikkelintegratie: https://wcagtool.nl/plugin. Vragen? Gebruik ons contactformulier: https://wcagtool.nl/contact — we reageren binnen 24 uur.

Probeer nu: open je site en plak de URL in onze checker. Ontvang een concrete foutlijst en code-oplossingen die je direct kunt implementeren.

Praktische tip: integreer de volgende kleine testroutine in je dev build om regressies te voorkomen — pasteable script voor de console:

(async function(){console.log('Start quick accessibility smoke test');const res=await fetch('https://wcagtool.nl/api/quick-scan?url='+encodeURIComponent(location.href));const json=await res.json();console.table(json.issues);alert('Accessibility quick-scan klaar — check console voor resultaten en bezoek https://wcagtool.nl/validator voor details');})();