Browser-Native Validation Catches Most Mistakes
Form Validation
HTML has built-in validation attributes — `required`, `type`, `pattern`, `min`, `max`. The browser handles error messages and blocks submit until they pass.
What you'll learn
- Apply built-in validation attributes
- Show validation hints to users
- Recognize when JS validation adds value
HTML has built-in form validation. The browser checks values on submit and refuses to send the form if anything fails.
Validation Attributes
| Attribute | Effect |
|---|---|
required | Must be filled in |
type | email, url, number, etc. enforce shape |
min / max | Range for numbers and dates |
minlength / maxlength | Character count limits |
pattern | A regex the value must match |
step | For numbers: enforce increments |
<form>
<label>Email
<input type="email" name="email" required />
</label>
<label>Username
<input
type="text"
name="username"
required
minlength="3"
maxlength="20"
pattern="[a-zA-Z0-9_]+"
title="Letters, numbers, and underscores only"
/>
</label>
<label>Age
<input type="number" name="age" min="13" max="120" />
</label>
<button>Sign up</button>
</form> Submitting with any invalid value shows the native error and stops submission.
Styling Validation States
CSS pseudo-classes:
input:invalid {
border-color: red;
}
input:valid {
border-color: green;
}
/* `:user-invalid` only applies AFTER the user has interacted */
input:user-invalid {
border-color: red;
} :user-invalid is the better default — :invalid fires before the
user has typed anything, which is rarely the right UX.
Custom Messages
You can replace the default browser message with JS:
input.addEventListener("invalid", () => {
if (input.validity.tooShort) {
input.setCustomValidity("Username must be at least 3 characters.");
} else {
input.setCustomValidity("");
}
}); When JS Validation Adds Value
Built-in validation is great for shape and presence. Reach for JS for:
- Async checks (does this username exist?)
- Cross-field rules (password and confirm-password must match)
- Showing inline errors instead of native popups
- Submitting valid data via
fetchwithout page reload
The HTML validation still runs first — JS extends it.
Skipping Validation
novalidate on the form:
<form action="/save" method="POST" novalidate>...</form> Useful when you handle validation entirely in JS.
Up Next
What happens when the form actually submits.
Form Submit →