playweb_

~ / journal/accessible-form-validation

Accessible form validation without a framework

// Editorial team

Most contact and submission forms need only a few rules: a required field, a minimum length, a valid URL. The browser already knows how to check all of them. The work is in reporting errors in a way everyone can follow.

Start with native constraints

Put the rules in the markup: required, type="url", minlength, pattern. That gives you input.validity for free, and the form still has sensible rules if your script fails to load. Add novalidate to the form only once your script is running, so the browser's own bubbles do not appear on top of yours.

form.noValidate = true;
form.addEventListener('submit', e => {
  const bad = [...form.elements].filter(el => el.willValidate && !el.checkValidity());
  bad.forEach(showError);
  if (bad.length) { e.preventDefault(); bad[0].focus(); }
});

Error text that screen readers hear

Give every field an empty element for its message, linked with aria-describedby. When the field fails, write the message into that element and set aria-invalid="true" on the field. When focus moves to the field, a screen reader reads the label, then the description, so the user hears what went wrong.

<label for="f-msg">Message</label>
<textarea id="f-msg" required minlength="20" aria-describedby="f-msg-err"></textarea>
<span class="err" id="f-msg-err"></span>

Write messages in plain words: "Please write at least 20 characters" rather than "Invalid input". Avoid relying on a red border alone. Around one in twelve men has some form of colour vision deficiency, and red borders are often missed.

When to validate

Checking on every keystroke makes people feel shouted at before they have finished typing. A pattern that works well:

  • Validate the whole form on submit.
  • After a field has shown an error once, re-check it on input so the message disappears as soon as it is fixed.
  • Do not validate a field on blur if the user has not typed anything yet.

Focus the first error

Moving focus to the first invalid field is the most useful single thing you can do. Keyboard and screen reader users land exactly where the problem is, and sighted users see the page scroll to it. If the form is long, a short summary at the top listing the errors as links also helps.

Do not stop there

Client-side checks are for the user's convenience. Anything that reaches a server still has to be validated there, because a request can be sent without your page at all. We cover the server side in our website build work.