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
- Input types and form attributes
- A practice form with labels and
nameattributes
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 addresstype="url"looks like a URL- number values respect
min,max, andstep - text length respects
minlengthandmaxlength patternregular expressions match
Example:
<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:
<label for="name">Name</label>
<input id="name" name="name" type="text" required>For a checkbox:
<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:
<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
<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
<label for="website">Website</label>
<input id="website" name="website" type="url" placeholder="https://example.com">Many browsers require a scheme like https://.
Number
<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
<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.
<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:
<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:
<input name="code" pattern="[A-Z]{3}-[0-9]{4}">Better:
<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:
<label for="username">Username</label>
<input id="username" name="username" minlength="3" required>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:
<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:
Browser validation -> better UX
Server validation -> data integrity and securityWarning
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:
- Mark required fields with
required. - Use
type="email"for email. - Add
minlengthto password or message fields. - Add one
patternplus visible help text. - 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.