Understandable: begrijpelijke websites bouwen

Toegankelijke formulieren implementeren — Praktische WCAG-guide | wcagtool.nl

Toegankelijke formulieren praktisch implementeren

Waarom dit vaak fout gaat: Formulieren missen vaak juiste label-associaties, foutafhandeling en focusmanagement. Dat leidt tot onbruikbare interfaces voor toetsenbordgebruikers, schermlezers en mensen met cognitieve beperkingen. Ontbrekende ARIA, verborgen foutmeldingen of alleen kleur als foutindicator zijn veelvoorkomende valkuilen.

Hoe wij dit oplossen: Wij geven stap-voor-stap codevoorbeelden (HTML/CSS/JS) die je direct kunt plakken, checklists die je kunt afvinken en testinstructies die je met onze WCAG checker/validator kunt valideren. Download onze plugin of test je pagina direct op wcagtool.nl/checker — bij vragen gebruik het contactformulier, we reageren binnen 24 uur.

Het probleem in de praktijk

Veelvoorkomende fouten

  • Labels niet gekoppeld (placeholder gebruikt als label).
  • Foutmeldingen alleen visueel (geen aria-live/role=alert).
  • Geen foutoverzicht voor lange formulieren; focus blijft op het veld met foutmelding ontbreekt.
  • Custom controls zonder juiste ARIA-rollen of keyboard support.
  • Contrast- of focus-stijlen ontbreken.

Waarom dat leidt tot faal

Schermlezers vinden geen context zonder label; toetsenbordgebruikers raken zoek zonder focusregels of overzicht; formulieren zonder aria-invalid of aria-describedby communiceren geen fouten effectief.

Zo los je dit op in code

1. Basisstructuur: labels, fieldset en legend

<form id="signup" novalidate>
  <fieldset>
    <legend>Account aanmaken</legend>
    <label for="email">E-mail</label>
    <input type="email" id="email" name="email" required autocomplete="email" inputmode="email" />
    <small id="email-hint">We sturen geen spam.</small>
  </fieldset>
</form>

Gebruik altijd een zichtbaar label en geef aanvullende context via aria-describedby (zoals hierboven met id=”email-hint”).

2. Foutmelding + error summary (testbare patroon)

<div id="form-error-summary" class="error-summary" role="alert" aria-live="assertive" aria-hidden="true">
  <h2 id="error-summary-title">Er zijn foutmeldingen in het formulier</h2>
  <ul id="error-list"></ul>
</div>
function showErrors(errors){
  const summary = document.getElementById('form-error-summary');
  const list = document.getElementById('error-list');
  list.innerHTML = '';
  errors.forEach(e => {
    const li = document.createElement('li');
    const a = document.createElement('a');
    a.href = '#'+e.id;
    a.textContent = e.message;
    a.addEventListener('click', (ev) => {
      ev.preventDefault();
      document.getElementById(e.id).focus();
    });
    li.appendChild(a);
    list.appendChild(li);

    const field = document.getElementById(e.id);
    field.setAttribute('aria-invalid','true');
    field.setAttribute('aria-describedby', (field.getAttribute('aria-describedby')||'') + ' ' + e.hintId);
  });
  summary.setAttribute('aria-hidden','false');
  summary.focus();
}

Belangrijke punten: focus naar de error summary en maak foutitems klikbaar om naar het veld te springen.

3. ARIA voor dynamische hints en fouten

<input id="username" name="username" aria-describedby="username-hint username-error" />
<small id="username-hint">5–20 tekens</small>
<div id="username-error" class="field-error" aria-live="polite"></div>

Gebruik aria-live op de individuele veldfout zodat schermlezers updates krijgen wanneer er live validatie plaatsvindt.

4. Keyboard & focus styles (CSS)

:focus { outline: 3px solid #005a9c; outline-offset: 2px; }
button:focus, a:focus { box-shadow: 0 0 0 3px rgba(0,90,156,0.25); }
.error-summary { border: 2px solid #c00; background:#fff3f3; padding:1rem; }
.field-error { color:#a00; }

5. Client-side validatie voorbeeld (concreet)

document.getElementById('signup').addEventListener('submit', function(e){
  e.preventDefault();
  const errors = [];
  const email = document.getElementById('email');
  if(!/^\S+@\S+\.\S+$/.test(email.value)){
    errors.push({id:'email', message:'Voer een geldig e-mailadres in', hintId:'email-error'});
    document.getElementById('email-error').textContent = 'Voer een geldig e-mailadres in';
  } else {
    email.removeAttribute('aria-invalid');
    document.getElementById('email-error').textContent = '';
  }
  if(errors.length){
    showErrors(errors);
    return;
  }
  // voer submit via Ajax of normaal door
});

Checklist voor developers

  • Labels: alle inputs hebben een <label for> of aria-label/aria-labelledby.
  • Hints: gebruik <small> of <div> met id en refereer via aria-describedby.
  • Fouten: foutoverzicht met role=”alert” en focus naar dat overzicht.
  • aria-invalid: zet op relevante velden bij fout.
  • Keyboard: alle custom controls reageren op Enter/Space/Arrow keys.
  • Contrast: zeker 4.5:1 voor bodytekst, check met onze WCAG checker/validator.
  • Focus: zichtbare focusstijl en niet verwijderen via outline: none zonder alternatief.
  • Form submission: gebruik server- en client-side validatie; zorg dat servererrors ook ARIA-vriendelijk zijn.

Tips voor designers en redacties

Gebruik van kleur en labels

Gebruik nooit alleen kleur om status aan te geven. Voeg iconen, tekst of patronen toe. Zorg dat labels zichtbaar blijven bij alle viewports en dat placeholders nooit als vervanging van labels worden gebruikt.

Microcopy en instructies

Schrijf korte, duidelijke instructies en plaats ze direct bij het veld. Voor redacties: gebruik onze plugin om content direct te scannen op leesbaarheid en alt-teksten. Download onze plugin op wcagtool.nl/plugin en test content automatisch.

Design patterns

Bij complexe componenten (datepickers, autocomplete) lever een ARIA-map: role, keyboard-interacties en update-strategie. Bij datepickers: laat input handmatig invullen (met inputmode) en geef fallback voor schermlezers.

Hoe test je dit?

Automatisch + handmatig

Start met automated tools: run axe-core, Lighthouse en onze WCAG checker/validator op wcagtool.nl/checker. Dit vind veel structurele issues snel.

Handmatige checks — stap-voor-stap

  1. Toetsenbord-only: navigeer volledig zonder muis. Formulier moet logisch tabben, Enter/Space starten acties, links in error summary werken.
  2. Schermlezer: test met NVDA (Windows) en VoiceOver (macOS/iOS). Controleer of labels, hints en fouten correct voorgelezen worden; controleer aria-live updates.
  3. Contrast: gebruik onze checker en meet 4.5:1 of 3:1 voor grote tekst.
  4. Foutpad: voer invalide waarden in, controleer error summary, focus verplaatst en aria-invalid gezet.
  5. Mobile: test op kleine schermen, virtueel toetsenbord en touch targets (min 44x44px).

Concrete testcases

1) Laat het veld e-mail leeg en submit: moet error summary tonen, focus naar summary en link naar het veld werkt. 2) Vul een ongeldig e-mailadres in: aria-live foutmelding bij net veld en aria-invalid=true. 3) Gebruik alleen toetsenbord voor interactieve widgets: alle acties zijn bereikbaar.

Extra code-snippets en patterns

Accessible custom checkbox

<div role="checkbox" tabindex="0" aria-checked="false" id="customCheckbox">Ik ga akkoord</div>
<script>
const cb = document.getElementById('customCheckbox');
cb.addEventListener('click', toggle);
cb.addEventListener('keydown', function(e){
  if(e.key === ' ' || e.key === 'Enter'){ e.preventDefault(); toggle(); }
});
function toggle(){ const state = cb.getAttribute('aria-checked') === 'true'; cb.setAttribute('aria-checked', String(!state)); }
</script>

Accessible date input (fallback)

<label for="date">Datum</label>
<input id="date" name="date" type="date" inputmode="numeric" pattern="\d{4}-\d{2}-\d{2}" aria-describedby="date-format" />
<small id="date-format">Gebruik YYYY-MM-DD als fallback</small>

Praktische quick-check voor implementatie

  1. Labels gekoppeld? (label[for] of aria-labelledby)
  2. aria-describedby voor hints/error IDs in place?
  3. Error summary met role=”alert” en focus verplaatst?
  4. aria-invalid toggles bij validatie?
  5. Focusvisible CSS aanwezig?
  6. Keyboard ondersteuning voor custom controls?
  7. Automated test pass via wcagtool.nl/checker?

Call-to-action en tools

Test je formulier nu direct met onze WCAG checker/validator op wcagtool.nl/checker en download de plugin voor jouw CMS op wcagtool.nl/plugin. Voor implementatievragen gebruik het contactformulier — we antwoorden binnen 24 uur.

Wil je dat wij jouw pagina live nakijken? Upload of test direct met onze validator en ontvang concrete oplossingen en codevoorstellen.

Laatste praktische tip

Implementatie-check: voeg één regel JS toe die bij submit alle velden met aria-invalid=”true” naar een array stopt en automatisch de error summary toont. Kopieer en plak dit als basis en run direct via onze checker:

function validateForm(form){
  const invalid = Array.from(form.querySelectorAll('[aria-invalid="true"],:invalid')).map(f => ({id:f.id,label:document.querySelector('label[for=\"'+f.id+'\"]').textContent||f.name}));
  if(invalid.length) showErrors(invalid.map(i => ({id:i.id,message:i.label + ' is ongeldig',hintId:i.id+'-error'})));
}

Test het meteen: open wcagtool.nl/checker, plak je HTML en bekijk de gedetailleerde fouten + concrete fixes. Voor snelle integratie: download de plugin op wcagtool.nl/plugin of vraag hulp via het contactformulier — antwoord binnen 24 uur.