Form Validation

Introduction

Form validation helps users fix mistakes before submission. HTML has built-in validation for required fields, email URLs, length, number ranges, and patterns. This chapter explains browser validation, novalidate, error-message UX, and why server-side validation is still required.

Prerequisites

What Browser Validation Does

Before submitting a form, the browser checks constraints such as:

  • required fields are not empty
  • type="email" looks like an email address
  • type="url" looks like a URL
  • number values respect min, max, and step
  • text length respects minlength and maxlength
  • pattern regular expressions match

Example:

html
<form action="/signup" method="post">
  <label for="email">Email</label>
  <input id="email" name="email" type="email" required>
 
  <button type="submit">Sign up</button>
</form>

Try submitting without an email. The browser blocks the request and shows its own message.

required

Use required when the field must be filled:

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

For a checkbox:

html
<label>
  <input type="checkbox" name="terms" value="accepted" required>
  I accept the terms
</label>

For radio groups, put required on one radio in the group:

html
<fieldset>
  <legend>Plan</legend>
  <label><input type="radio" name="plan" value="free" required> Free</label>
  <label><input type="radio" name="plan" value="pro"> Pro</label>
</fieldset>

Type-Based Validation

Email

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

This checks a basic email shape. It does not prove the mailbox exists.

URL

html
<label for="website">Website</label>
<input id="website" name="website" type="url" placeholder="https://example.com">

Many browsers require a scheme like https://.

Number

html
<label for="age">Age</label>
<input id="age" name="age" type="number" min="13" max="120" required>

The browser checks numeric range before submit.

Length Constraints

html
<label for="username">Username</label>
<input id="username" name="username" type="text" minlength="3" maxlength="20" required>

Use length constraints for:

  • usernames
  • short titles
  • codes
  • comments with practical size limits

Add visible help text so users know the rule before failing.

html
<p id="username-help">Use 3 to 20 characters.</p>
<input
  id="username"
  name="username"
  type="text"
  minlength="3"
  maxlength="20"
  aria-describedby="username-help"
>

Pattern Validation

pattern uses a regular expression:

html
<label for="zip">US ZIP code</label>
<input
  id="zip"
  name="zip"
  type="text"
  pattern="[0-9]{5}"
  inputmode="numeric"
  aria-describedby="zip-help"
>
<p id="zip-help">Enter a 5-digit ZIP code, such as 94105.</p>

Patterns are powerful but easy to overuse. Keep them simple and explain them.

Bad pattern UX:

html
<input name="code" pattern="[A-Z]{3}-[0-9]{4}">

Better:

html
<label for="code">Invite code</label>
<input id="code" name="code" pattern="[A-Z]{3}-[0-9]{4}" aria-describedby="code-help">
<p id="code-help">Format: ABC-1234.</p>

Custom Error Text (Light Preview)

Plain HTML uses browser-provided error messages. JavaScript can customize them with Constraint Validation API:

html
<label for="username">Username</label>
<input id="username" name="username" minlength="3" required>
js
const username = document.querySelector("#username");
 
username.addEventListener("input", () => {
  username.setCustomValidity("");
 
  if (username.validity.tooShort) {
    username.setCustomValidity("Username must be at least 3 characters.");
  }
});

This is a JavaScript topic, but HTML constraints provide the rules JavaScript can read.

novalidate

Disable built-in validation:

html
<form action="/signup" method="post" novalidate>
  ...
</form>

Use novalidate when your app has fully custom validation UX. Do not add it casually; you lose useful browser behavior.

Error Message UX

Good validation helps users succeed:

  • explain rules before submit
  • mark required fields clearly
  • place errors near the field
  • preserve user input after errors
  • do not rely on color alone
  • move focus thoughtfully to the first invalid field

HTML alone cannot do all of this, but it starts the process with semantic controls and constraints.

Server Validation Is Mandatory

Frontend validation improves user experience. It does not protect data.

Users can:

  • disable JavaScript
  • edit HTML in DevTools
  • send requests with curl
  • bypass the browser entirely

Every backend must validate again:

text
Browser validation -> better UX
Server validation  -> data integrity and security

Warning

Never Trust Client Input

HTML validation is helpful but not authoritative. Treat every submitted value as untrusted on the server.

Complete Example

Mini Exercise

Add validation to your contact or signup form:

  1. Mark required fields with required.
  2. Use type="email" for email.
  3. Add minlength to password or message fields.
  4. Add one pattern plus visible help text.
  5. Submit invalid data and observe browser messages.

FAQ

Does type="email" guarantee a real email address?

No. It checks basic format only. The server may still need email verification.

Should I use pattern for passwords?

Be careful. Complex password patterns produce confusing errors. Prefer length rules plus clear guidance, and validate on the server.

Why does my custom JavaScript validation not run?

The browser may stop submission first because built-in validation fails. Use valid constraints, handle invalid events, or add novalidate only when building a full custom validation system.

Can CSS style invalid fields?

Yes, with pseudo-classes such as :invalid, :valid, and :required. That belongs to CSS, but HTML constraints enable those states.

What comes next?

Accessible forms — labels, fieldsets, errors, groups, and keyboard behavior.