Ga naar inhoud
·2 min

WCAG toegankelijkheid: van vinkjeslijst naar gewoonte

Hoe je WCAG 2.1 AA niet als bureaucratie behandelt maar als kwaliteitsmaatstaf. Praktische patronen die ik gebruik in elk project.

ToegankelijkheidWCAGFrontendBest Practices

Toegankelijkheid heeft een imagoprobleem. Het wordt gezien als extra werk, een set regels die je na het bouwen moet afvinken, iets voor grote overheidsprojecten.

Na jaren van bouwen aan platformen voor miljoenen gebruikers — en het bouwen van AllyScan, een tool specifiek voor toegankelijkheidstesting — ben ik tot een andere conclusie gekomen: WCAG-compliance is gewoon goede code schrijven.

Waarom het ertoe doet

In Nederland heeft ongeveer 1 op de 6 mensen een functiebeperking die invloed heeft op hoe ze het web gebruiken. Visuele beperkingen, motorische beperkingen, dyslexie, epilepsie — het spectrum is breed.

Maar ook zonder beperking profiteer je van toegankelijke code:

  • Betere SEO: Semantische HTML en beschrijvende alt-teksten helpen zoekmachines
  • Verbeterde keyboard navigatie: Prettig voor power users, noodzakelijk voor anderen
  • Robustere code: Toegankelijke componenten zijn doorgaans beter doordacht

De patronen die ik overal gebruik

1. Semantische HTML als fundament

Voor accessibility geldt: gebruik het juiste element voor de juiste taak. Een <button> voor acties, een <a> voor navigatie, <nav> voor navigatieblokken.

// ❌ Niet dit
<div onClick={handleSubmit} className="btn">
  Versturen
</div>
 
// ✅ Maar dit
<button type="submit" onClick={handleSubmit}>
  Versturen
</button>

Het verschil: de button is automatisch focussable, reageert op Enter/Space, en schermlezer kondigt hem aan als button.

2. Focus management

Modale dialogen, drawers en dynamische content vereisen bewust focus management:

export function Modal({ isOpen, onClose, children }: ModalProps) {
  const firstFocusableRef = useRef<HTMLButtonElement>(null);
 
  useEffect(() => {
    if (isOpen) {
      // Focus het eerste interactieve element bij openen
      firstFocusableRef.current?.focus();
    }
  }, [isOpen]);
 
  return isOpen ? (
    <div
      role="dialog"
      aria-modal="true"
      aria-labelledby="modal-title"
      // Voorkom focus buiten de modal
      onKeyDown={(e) => e.key === 'Escape' && onClose()}
    >
      <button ref={firstFocusableRef} onClick={onClose} aria-label="Sluit modal">
        ×
      </button>
      <h2 id="modal-title">{title}</h2>
      {children}
    </div>
  ) : null;
}

3. Kleurcontrast automatisch checken

Handmatig kleurcontrast controleren is tijdrovend en foutgevoelig. Ik gebruik een combinatie van:

  • Storybook met @storybook/addon-a11y voor visuele controle per component
  • axe-core in Jest tests voor geautomatiseerde checks
  • AllyScan voor productiesites (mijn eigen tool)
// Toegankelijkheidstest in Jest
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
 
it('Button has no accessibility violations', async () => {
  const { container } = render(<Button>Versturen</Button>);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

4. Alt-teksten die betekenis toevoegen

// ❌ Nutteloos
<img src="leroy.jpg" alt="afbeelding" />
 
// ❌ Te beschrijvend
<img src="leroy.jpg" alt="Een foto van een man met bruin haar die naar de camera kijkt" />
 
// ✅ Context-gedreven
<img src="leroy.jpg" alt="Leroy Steding, Senior Full-Stack Developer" />
 
// ✅ Decoratief? Dan leeg laten.
<img src="decorative-wave.svg" alt="" role="presentation" />

5. ARIA alleen als nodig

Een veelgemaakte fout is ARIA overal toevoegen. De eerste regel van ARIA gebruik: gebruik geen ARIA als je een native HTML element kunt gebruiken.

// ❌ Overbodig
<button aria-role="button">Klik hier</button>
 
// ✅ Nuttig: status melden aan schermlezer
<button aria-pressed={isActive} onClick={toggle}>
  {isActive ? 'Aan' : 'Uit'}
</button>

AllyScan: toegankelijkheid automatiseren

Dit is precies waarom ik AllyScan heb gebouwd. Een CI/CD pipeline die na elke deployment automatisch je volledige site doorscant op WCAG 2.1 AA/AAA overtredingen, met een Chrome-extensie voor realtime feedback tijdens het ontwikkelen.

Het principe: maak het onmogelijk om ontoegankelijke code te mergen.

# .github/workflows/accessibility.yml
- name: Run AllyScan
  run: npx allyscan --url ${{ env.DEPLOY_URL }} --standard WCAG21AA
  env:
    ALLYSCAN_TOKEN: ${{ secrets.ALLYSCAN_TOKEN }}

Hoe je ermee start

  1. Installeer de axe DevTools browser extensie — gratis, geeft direct feedback
  2. Navigeer je site met alleen het toetsenbord — Tab, Shift+Tab, Enter, Space, pijltoetsen. Is alles bereikbaar?
  3. Zet een schermlezer aan — NVDA (Windows, gratis), VoiceOver (Mac/iOS, ingebouwd), TalkBack (Android)
  4. Voeg jest-axe toe aan je bestaande test suite

Toegankelijkheid hoeft niet perfect te zijn op dag één. Maar het moet wel structureel verbeteren. Begin klein, maak het onderdeel van je definition of done, en bouw het in je tooling.

Je gebruikers — alle gebruikers — verdienen het.

Plan een gesprek