Form Validation
Long before JavaScript frameworks had validation libraries, HTML already
had a built-in system for it. A handful of attributes — required,
pattern, minlength/maxlength, min/max — tell the browser what a
valid value looks like, and the browser blocks submission and shows a
native error message when a field doesn't qualify. It's not a replacement
for server-side validation, but it catches the vast majority of mistakes
for free, with no JavaScript at all.
required
The simplest validation attribute: the field must have a value before the form can submit.
required.html
<form> <label for="email">Email</label> <input type="email" id="email" name="email" required /> <button type="submit">Sign up</button> </form>
Try submitting this form empty and the browser shows a native tooltip like "Please fill out this field" and refuses to submit — no JavaScript required.
pattern — Regular Expression Matching
pattern takes a JavaScript-flavored regular expression (without the
surrounding slashes) that the field's value must fully match.
pattern.html
<label for="zip">US ZIP code</label>
<input
type="text"
id="zip"
name="zip"
pattern="[0-9]{5}(-[0-9]{4})?"
title="Enter a 5-digit ZIP code, optionally followed by -1234"
required
/>title attribute's text is shown as part of the browser's native validation message when the pattern doesn't match — always include one, or the visitor only sees "match the requested format" with no clue what that format is.minlength / maxlength
These constrain the number of characters typed. Unlike maxlength, which
also stops the browser from letting the user type past the limit,
minlength is purely a validation check on submit.
minlength-maxlength.html
<label for="password">Password</label> <input type="password" id="password" name="password" minlength="8" maxlength="64" required />
min / max for Numbers
For number, range, and date/time input types, min and max set the
acceptable bounds. A step attribute can further restrict the value to a
multiple of a given increment.
min-max.html
<label for="quantity">Quantity (1–10)</label> <input type="number" id="quantity" name="quantity" min="1" max="10" step="1" value="1" />
Common Validation Attributes at a Glance
Attribute | Applies to | Checks |
|---|---|---|
| Most input types, | A value is present |
| Text-like inputs | Value matches a regular expression |
| Text-like inputs, | Character count bounds |
|
| Numeric or date value bounds |
|
| Value is a valid increment from |
| Those specific input types | Value matches the expected format |
The Browser's Native Validation UI
When a form with invalid fields is submitted, the browser automatically:
Cancels the submission before it reaches the server.
Focuses the first invalid field.
Shows a small native tooltip explaining the problem (wording and appearance differ per browser).
Please fill out this field. Please match the requested format: Enter a 5-digit ZIP code, optionally followed by -1234
Styling With :valid and :invalid
CSS pseudo-classes let you style a field based on its current validity state, without any JavaScript.
valid-invalid.css
input:invalid {
border-color: #d64545;
}
input:valid {
border-color: #2e7d32;
}
/* Avoid shaming the user before they've typed anything */
input:placeholder-shown:invalid {
border-color: initial;
}:invalid the instant the page loads, before the user has done anything wrong. The :placeholder-shown:invalid combinator above is a common trick to suppress the "invalid" styling until the field has actually been touched and left in a bad state — even better is toggling styles in response to the blur or submit event with JavaScript.A Complete Example
validation-example.html
<form novalidate id="signup-form">
<label for="username">Username</label>
<input
type="text"
id="username"
name="username"
pattern="[a-zA-Z0-9_]{3,16}"
title="3-16 characters: letters, numbers, underscore"
required
/>
<label for="email">Email</label>
<input type="email" id="email" name="email" required />
<label for="age">Age</label>
<input type="number" id="age" name="age" min="13" max="120" required />
<button type="submit">Create account</button>
</form>novalidate to the <form> turns off the browser's automatic validation UI so you can drive it entirely through JavaScript instead — useful when you want fully custom error messages while still keeping the same HTML validation attributes as your source of truth (see the Constraint Validation API tutorial).