How do you validate a form natively?
By FrontendPro Editorial Team Updated 9/26/2026
Answer
Start with HTML attributes — the browser validates them for free, before any JavaScript runs:
<input type="email" required minlength="5" maxlength="80">
<input type="number" min="1" max="10" step="1">
<input pattern="[0-9]{3}-[0-9]{4}" title="Format: 123-4567">
Reading the result in JavaScript
input.checkValidity(); // true/false, fires an "invalid" event if false
input.reportValidity(); // same, and shows the browser's bubble
input.validationMessage; // the localised message
input.validity.valueMissing; // which constraint failed
input.validity.typeMismatch;
input.validity.tooShort;
input.validity.patternMismatch;
The validity object is what lets you write your own message per failure reason rather than one generic string.
Custom rules
setCustomValidity marks a field invalid with your own text. The important part is clearing it, otherwise the field stays invalid forever:
confirm.addEventListener("input", () => {
confirm.setCustomValidity(
confirm.value === password.value ? "" : "Passwords do not match"
);
});
Replacing the default bubbles
Add novalidate to the form to suppress the browser UI while keeping the API:
<form novalidate>
form.addEventListener("submit", (e) => {
if (!form.checkValidity()) {
e.preventDefault();
for (const el of form.elements) showError(el, el.validationMessage);
}
});
Style states with :invalid, or better :user-invalid, which only applies after the user has interacted — so an empty form does not light up red before anyone has typed.
Never trust it
Client-side validation is for user experience only. Anyone can bypass the form and post directly to your endpoint, so every rule must be enforced again on the server.
