Codeskill

Learn to code, step by step

Forms and the constraint validation API

We’ll look at the HTML constraint validation API. Built-in form rules, custom messages, and JavaScript hooks that work with native browser behaviour instead of fighting it.

Built-in constraints

<form id="signup" novalidate>
  <label>
    Email
    <input name="email" type="email" required autocomplete="email">
  </label>
  <label>
    Age
    <input name="age" type="number" min="13" max="120" required>
  </label>
  <button type="submit">Create account</button>
</form>

novalidate on the form lets you handle submission in JS while still using each field’s validation API. Without it, the browser blocks submit and shows native bubbles.

Checking validity in JavaScript

const form = document.querySelector('#signup');

form.addEventListener('submit', (event) => {
  event.preventDefault();
  if (!form.checkValidity()) {
    form.reportValidity();
    return;
  }
  submitForm(new FormData(form));
});

Custom messages

const email = form.elements.email;

email.addEventListener('input', () => {
  if (email.validity.valueMissing) {
    email.setCustomValidity('We need an email to create your account.');
  } else if (email.validity.typeMismatch) {
    email.setCustomValidity('That does not look like an email address.');
  } else {
    email.setCustomValidity('');
  }
});

Always clear custom validity on valid input – otherwise the field stays invalid forever.

validity flags

  • valueMissing – required empty field
  • typeMismatch – wrong type (email, url)
  • patternMismatch – regex pattern failed
  • tooShort / tooLong – length constraints
  • rangeUnderflow / rangeOverflow – number/date min/max

Showing errors in your UI

Native bubbles are fine for quick prototypes. Product sites usually render inline errors and tie them to inputs with aria-invalid and aria-describedby. Read validity flags, map them to messages, focus the first invalid field.

function showFieldError(input, message) {
  input.setAttribute('aria-invalid', 'true');
  const hint = document.querySelector(`#${input.id}-error`);
  hint.textContent = message;
  input.setAttribute('aria-describedby', hint.id);
}

Next: browser storage – localStorage, sessionStorage, and a sensible intro to IndexedDB.

PreviousEvents (delegation, custom, cleanup)