Het verschil tussen WCAG

Toegankelijke formulieren — Praktische implementatie | wcagtool.nl

Toegankelijke formulieren: praktische implementatie

Formulieren zijn puntsgewijs de grootste bron van toegankelijkheidsfouten: ontbrekende labels, onduidelijke foutmeldingen, niet-toegankelijke focusflow en reliance op kleur alleen. Developers en designers weten vaak wát de WCAG-eis is, maar missen concrete, testbare patterns die werken met moderne JS-frameworks en CMS’en.

Wij bieden directe, herbruikbare oplossingen: compacte HTML-structuren, CSS-focusregels, ARIA-patronen en JavaScript-helpers voor validatie en focus-management. Test je site direct met onze WCAG checker, download onze plugin via de plugin-pagina en neem contact op via het contactformulier — vragen worden binnen 24 uur beantwoord.

Het probleem in de praktijk

Veelvoorkomende fouten

  • Labels ontbreken of visueel verborgen zonder accessible-name (schending van 1.3.1 en 4.1.2).
  • Fouten zijn alleen kleur-gebaseerd of visueel, zonder tekstuele aanwijzing of focus-verplaatsing (schending van 1.4.1 en 3.3.1).
  • Dynamic content (AJAX) updates zonder aria-live of role=”alert” — screenreaders missen updates (schending 4.1.3 / 3.2.2).
  • Keyboard flow ontbreekt: custom controls vangen focus niet correct of zijn niet bedienbaar (2.1.1).

Waarom dat leidt tot problemen

Ontbrekende accessible names en verkeerd gebruik van ARIA leiden tot onbruikbare formulieren voor screenreadergebruikers. Onvoldoende focus-management betekent dat gebruikers niet worden geleid naar fouten, wat conversie en toegankelijkheid schaadt. Designers gebruiken vaak visuele hints (kleur/icoon) zonder tekst of aria-describedby referenties.

Zo los je dit op in code

Standaard HTML-structuur met labels en fieldsets

Gebruik semantische HTML waar mogelijk. Voor groepen radio/checkboxes: fieldset + legend. Voor inputs: label met for of wikkel input in label.

<form id="signup" novalidate>
  <fieldset>
    <legend>Contactgegevens</legend>
    <label for="email">E-mailadres</label>
    <input id="email" name="email" type="email" required aria-describedby="email-desc email-error">
    <div id="email-desc">We gebruiken dit om je account te verifiëren.</div>
    <div id="email-error" class="error" aria-live="polite"></div>
  </fieldset>
  <button type="submit">Verstuur</button>
</form>

Toegankelijke foutmelding en focus naar eerste fout (JS)

Valideer client-side, markeer velden met aria-invalid en zet focus op het eerste invalid veld. Plaats fouttekst in een element met role=”alert” of aria-live=”assertive” wanneer je directe aandacht wilt.

document.getElementById('signup').addEventListener('submit', function(e){
  e.preventDefault();
  const form = e.target;
  const fields = Array.from(form.querySelectorAll('input,select,textarea'));
  let firstInvalid = null;
  fields.forEach(f => {
    const errorEl = document.getElementById(f.id + '-error');
    // eenvoudige validatie
    if(f.hasAttribute('required') && !f.value.trim()){
      f.setAttribute('aria-invalid','true');
      if(errorEl){ errorEl.textContent = 'Dit veld is verplicht.'; }
      if(!firstInvalid) firstInvalid = f;
    } else {
      f.removeAttribute('aria-invalid');
      if(errorEl){ errorEl.textContent = ''; }
    }
  });
  if(firstInvalid){
    firstInvalid.focus();
    // optioneel: scroll naar zichtbaar
    firstInvalid.scrollIntoView({behavior:'smooth', block:'center'});
    return;
  }
  // do submit
  form.submit();
});

Gebruik aria-describedby voor aanvullende instructies en fouten

Combineer instructies en foutmeldingen via aria-describedby (meerdere ids scheiden met spaties). Dit geeft screenreaders context bij focus.

<input id="password" name="password" type="password" required aria-describedby="pwd-help pwd-error">
<div id="pwd-help">Minimaal 8 tekens, 1 cijfer.</div>
<div id="pwd-error" aria-live="polite"></div>

CSS: focus-visible en contrast voor foutstaten

Zorg dat focus duidelijk zichtbaar is en dat foutkleuren voldoende contrast hebben naast tekst- of icoonherkenning.

input:focus{
  outline: 3px solid #005fcc; /* hoge zichtbaarheid */
  outline-offset: 2px;
}
.error{
  color:#a80000; /* test contrast: AA/AAA volgens WCAG */
}
.invalid{ border-color:#a80000; } /* gebruik niet alleen kleur: combineer met icon/text */

ARIA: wanneer wél en wanneer niet

Gebruik ARIA alleen als native HTML niet volstaat. Voor dynamische foutmeldingen: role=”alert” of aria-live. Voor custom controls: implementeer keyboard handlers en exposeer juiste role/aria-attributes (role=”switch”, aria-checked, tabindex, keyboard handlers).

<div role="alert" aria-live="assertive" id="global-error"></div>

Checklist voor developers

  • Labels: elk form control heeft een expliciet label of aria-label/aria-labelledby (controleer 4.1.2).
  • Instructions: geef hulptekst in aria-describedby en leesbaar zichtbaar bij focus.
  • Foutmeldingen: tekstueel, gekoppeld via aria-describedby, en focus naar eerste fout (3.3.1/3.3.3).
  • Keyboard: alle controls navigeren en activeren via keyboard (2.1.1).
  • Live updates: dynamische foutmeldingen en serverresponses via aria-live/role=”alert”.
  • Visuele hints: gebruik niet alleen kleur; voeg iconen/tekst/outline toe (1.4.1).
  • Test: screenreader + keyboard + contrast checker + onze WCAG checker.

Tips voor designers en redacties

Design-systeem patterns

Maak herbruikbare form components met ingebouwde aria-describedby en fout placeholders. Definieer tokens voor foutkleuren met voldoende contrast en focus-states in de component-bibliotheek.

Content-writer rules

  • Schrijf korte, duidelijke foutmeldingen: “E-mailadres ontbreekt” of “Gebruik een geldig e-mailadres”.
  • Vermijd technische termen; geef actiegerichte suggesties.
  • Voeg voorbeelden en formaatrestricties toe in de help-text (aria-describedby).

Voorbeeld design-token (SCSS)

$color-focus: #005fcc;
$color-error: #a80000;
.form-input:focus{
  box-shadow: 0 0 0 3px rgba(0,95,204,0.2);
}
.form-error{ color: $color-error; }

Hoe test je dit?

Stappen voor handmatige tests

  1. Keyboard-only: navigeer het formulier met Tab/Shift+Tab en activeer submit met Enter/Space.
  2. Screenreader: test met NVDA (Windows) of VoiceOver (macOS). Focus op elk veld en controleer dat label + descriptions + fouten worden uitgesproken.
  3. Simuleer fouten: laat required velden leeg en controleer aria-invalid, focus-verplaatsing en error text.
  4. Contrast: gebruik contrasttool (of onze WCAG checker) voor fout- en focuskleuren.
  5. Automated: run je build met accessibility linter en CI met onze plugin; download via plugin.

Concrete test-cases

  • Case A: Verwijder email value, submit → verwacht: aria-invalid op #email, focus shift naar email, #email-error bevat tekst en wordt voorgelezen.
  • Case B: Gebruik alleen kleur om fout aan te geven → FAIL; controleer dat er ook tekst/icoon aanwezig is.
  • Case C: Dynamische serverfout (e.g. email in gebruik) → server response in <div role=”alert”> met focus-behandeling of duidelijke aanwijzing.

Automated checks in CI

Integreer axe-core of pa11y in je pipeline en combineer met onze WCAG checker voor live-omgevingen. Voeg tests die checken op aria-describedby aanwezigheid, labels en tabindex volgorde.

// voorbeeld: simple axe in jest
import {configureAxe} from 'jest-axe';
const axe = configureAxe({rules:{'label-req-for':{enabled:true}}});
// gebruik in je component tests

Laatste praktische tip (direct toepasbaar)

Gebruik dit korte helper-script als basis in elke site: valideer required velden, zet aria-invalid, vul fouttekst en verplaats focus naar de eerste fout — drop-in in je asset pipeline en combineer met onze checker.

// Minimal helper: voeg deze aan je common JS
export function validateForm(form){
  const fields = Array.from(form.querySelectorAll('[required]'));
  let firstInvalid=null;
  fields.forEach(f => {
    const err = document.getElementById(f.id + '-error');
    if(!f.value.trim()){
      f.setAttribute('aria-invalid','true');
      if(err) err.textContent = 'Vul dit veld in.';
      if(!firstInvalid) firstInvalid=f;
    } else {
      f.removeAttribute('aria-invalid');
      if(err) err.textContent = '';
    }
  });
  if(firstInvalid){
    firstInvalid.focus();
    return false;
  }
  return true;
}

Test je implementatie nu met onze WCAG checker, download de plugin voor CI en neem bij vragen contact op via ons contactformulier — wij antwoorden binnen 24 uur.