Tips・Publishing your work

The basics of form validation

Sent empty, or with "a" in the email field — HTML attributes alone handle a surprising amount of validation. The built-in features, how to show state in CSS, and adding your own checks in JavaScript.

Sent empty, or with “a” typed into the email field—adding a few HTML attributes hands most of this to the browser. Start there.

What attributes alone can do

<form>
  <label for="name">Name</label>
  <input type="text" id="name" name="name" required>

  <label for="email">Email</label>
  <input type="email" id="email" name="email" required>

  <label for="zip">Postcode</label>
  <input type="text" id="zip" name="zip" pattern="\d{5}" placeholder="12345">

  <button type="submit">Send</button>
</form>

That alone makes the browser stop an empty submission and say so.

AttributeWhat it checks
requiredThat it isn’t empty
type="email"That it looks like an email address
type="url"That it looks like a URL
type="number" + min / maxThat it’s a number, within a range
minlength / maxlengthCharacter count limits
pattern="…"That it matches a shape you define (a regular expression)
Press it while empty and a bubble points at the field. Fill things in correctly and the borders turn green.

Showing “valid” and “invalid” in CSS

The browser exposes the state so you can style it.

input:user-invalid {
  border-color: #e5484d;   /* red once they've typed something invalid */
}
input:user-valid {
  border-color: #3aa76d;   /* green once it's valid */
}
AccessibilityReadable colors, unreadable colors (contrast)More on not relying on colour, in the accessibility course

Adding your own checks in JavaScript

Checks the attributes can’t express—“do these two password fields match?”—go in JavaScript.

const form = document.querySelector("#signup");
const pass = document.querySelector("#pass");
const confirm = document.querySelector("#confirm");

form.addEventListener("submit", function (event) {
  if (pass.value !== confirm.value) {
    event.preventDefault();
    document.querySelector("#error").textContent = "The passwords don't match";
  }
});

To put your own wording in the browser’s own bubble, use setCustomValidity().

confirm.addEventListener("input", function () {
  if (confirm.value !== pass.value) {
    confirm.setCustomValidity("The passwords don't match");
  } else {
    confirm.setCustomValidity("");   // empty string means "no problem"
  }
});

Validation is not a security measure

Writing error messages people can act on

The same error reads very differently depending on the words.

✕ Dismissive○ Tells them what to do
Invalid inputCheck the format of the email address
Bad valueThe postcode should be five digits, like 12345
RequiredPlease enter your name
  • Where the problem is (put it next to the field)
  • What was expected (shape, length)
  • How to fix it

That’s enough. Equally important: don’t wipe what they typed. A form that empties itself on every error is a form nobody finishes.

AccessibilityAlways give a form a labelTying labels to fields properlyTipsMaking your contact form actually sendMaking the form actually send once it passes

Summary

  1. Start with HTML attributes (required, type, pattern)—the browser checks for free
  2. Show state with :user-invalid and :user-valid, and never with colour alone
  3. Browser-side checks are courtesy, not security. The receiving side has to validate

How carefully you handle validation shows up directly in how many people finish your form.

FAQ

Can I validate a form without JavaScript?
Yes. Attributes like required, type="email", and pattern are enough for the browser to check before submitting and show an error.
Can I change the wording of the browser's error messages?
Yes, with setCustomValidity in JavaScript. The default wording varies by browser and language, so anything you need people to read should be shown by your own code.
Does validating a form make it secure?
No. Browser-side checks can be removed in seconds with dev tools. Validation for security has to happen where the data is received (on the server).