HTML Constraint Validation API: Complete Guide with Examples
Form validation is a cornerstone of user-friendly web development. While HTML5 provides basic built-in validation, the HTML Constraint Validation API gives developers surgical control over error messages, validation timing, and error handling — all without a single external library or backend round-trip.

This guide walks through every feature of the API with working code examples, so you can implement it confidently today.
Table of Contents
- Why Use the HTML Constraint Validation API?
- 1. HTML5 Validation Attributes — The Foundation
- 2.
checkValidity()andreportValidity() - 3. Custom Error Messages with
setCustomValidity() - 4. The
validityProperty — Pinpoint the Exact Error - 5. The
willValidateProperty - Live CodePen Demo
- Comparison: Default vs. API Validation
- Best Practices
- Conclusion
Why Use the HTML Constraint Validation API?
HTML5 introduced attributes like required, pattern, and type for validation — but they have real limits. Error messages are browser-generated and often vague. Validation fires automatically on submit, giving you no control over timing.
The Constraint Validation API solves all of this:
- Customizable feedback — replace generic browser messages with helpful, specific prompts
- Controlled timing — validate on
blur, oninput, or only at submission - Granular error detection — know exactly why an input failed, not just that it did
1. HTML5 Validation Attributes — The Foundation
Before reaching for JavaScript, HTML5 attributes give you a free validation baseline:
| Attribute | What it enforces |
|---|---|
required | Field must not be empty |
type="email" / type="url" | Input must match the format |
min / max / step | Numeric range and interval |
pattern | Input must match a regex |
minlength / maxlength | Character length limits |
These attributes work hand-in-hand with the API — they define the constraints; the API lets you control and customize how those constraints are reported.
2. checkValidity() and reportValidity()
These two methods are the core of the API:
checkValidity()— returnstrueif all constraints pass,falseif any fail. Silent — no UI shown.reportValidity()— same check, but also triggers browser error UI for any failing fields.
Call them on either an individual input or the entire <form> element.
const form = document.querySelector("form");
form.addEventListener("submit", (event) => {
if (!form.checkValidity()) {
event.preventDefault(); // stop submission
form.reportValidity(); // show built-in messages
}
});
Why this matters: adding novalidate to your <form> tag disables the browser’s automatic validation on submit, putting you fully in control of when and how feedback appears.
3. Custom Error Messages with setCustomValidity()
This is the API’s most used feature. Pass a non-empty string to show a custom error; pass an empty string to clear it.
const emailInput = document.querySelector("input[type='email']");
emailInput.addEventListener("input", () => {
if (emailInput.validity.typeMismatch) {
emailInput.setCustomValidity(
"Please use the format name@example.com"
);
} else {
emailInput.setCustomValidity(""); // valid — clear the error
}
});
⚠️ Always clear the custom message (set it to
"") once the input becomes valid — otherwisecheckValidity()will keep returningfalseeven for correct input.
4. The validity Property — Pinpoint the Exact Error
Every form element exposes a validity object — a ValidityState — with Boolean flags for each possible failure reason:
| Property | true when… |
|---|---|
valueMissing | A required field is empty |
typeMismatch | Input doesn’t match type (e.g. bad email) |
patternMismatch | Input doesn’t match pattern regex |
tooShort / tooLong | Length outside minlength/maxlength |
rangeUnderflow / rangeOverflow | Number outside min/max |
stepMismatch | Number doesn’t align with step |
customError | A custom message is set via setCustomValidity() |
valid | All constraints pass |
Example — different messages for different failures:
const username = document.querySelector("#username");
username.addEventListener("blur", () => {
if (username.validity.valueMissing) {
username.setCustomValidity("Username is required.");
} else if (username.validity.tooShort) {
username.setCustomValidity(
`At least ${username.minLength} characters needed — you have ${username.value.length}.`
);
} else {
username.setCustomValidity("");
}
username.reportValidity();
});
This is far more helpful than a generic “Please fill in this field.”
5. The willValidate Property
A simple Boolean that tells you whether a given element participates in constraint validation at all. Elements with disabled, hidden, or outside a form will return false.
const input = document.querySelector("input");
if (input.willValidate) {
console.log("This field will be validated on submit.");
} else {
console.log("This field is excluded from validation.");
}
Most useful in dynamic forms where you conditionally disable fields.
Live CodePen Demo
The demo below puts all five features together: a registration form with custom error messages, real-time blur validation, and a novalidate-controlled submit flow.
→ Open and fork the demo on CodePen
See the Pen Constraint Validation API by Shakil Alam (@Itxshakil) on CodePen.
Comparison: Default vs. API Validation
| Feature | Default Browser Validation | Constraint Validation API |
|---|---|---|
| Error messages | Generic, browser-defined | Fully custom via setCustomValidity() |
| Validation timing | Auto on submit only | Any event (blur, input, submit) |
| Error detail | None | 8 specific validity flags |
| JavaScript integration | Minimal | Full — build any custom flow |
| Accessibility | Standard browser UI | aria-live, custom announcements |
| Browser support | Universal | 97%+ globally |
Best Practices
Start with HTML attributes. required, type, minlength, pattern — these are free and accessible. The API layers on top.
Add novalidate when going custom. Prevents the browser from showing its own messages before yours.
Always clear setCustomValidity("") on valid input. Failing to do this is the most common bug — the field looks fine but checkValidity() still returns false.
Validate on blur, not just submit. Catching errors field-by-field as the user moves on feels far less frustrating than a wall of errors at the end.
Use aria-live="polite" on error containers. Screen readers will announce the message automatically when it’s injected, no extra code needed.
Write friendly messages. “Your email is missing an ‘@’ — could you add it?” beats “Invalid email” every time.
Conclusion
The HTML Constraint Validation API gives you everything you need to build forms that feel considerate — custom messages, flexible timing, and pinpoint error detection — without a single dependency. Start with the HTML attributes for structure, layer in setCustomValidity() for messaging, and use the validity flags for precision.
The live demo above has all five features working together. Fork it, adapt it to your forms, and your users will thank you.
Further reading:





One Comment