Long before JavaScript validation libraries, browsers already implement a complete, native Constraint Validation API. Understanding it first often eliminates the need for a library entirely, or at minimum informs a much simpler custom implementation.
1Every Field Has A Built-In validity Object
Every form control element ā <input>, <select>, <textarea> ā automatically exposes a read-only .validity property, a ValidityState object with named boolean flags reflecting exactly which HTML5 validation constraints (if any) the current value fails: valueMissing for an empty required field, typeMismatch for a malformed email or URL, patternMismatch for a value failing a pattern attribute, tooShort/tooLong for length constraints, and several others.
This means inspecting *why* a field is invalid requires zero custom logic ā the browser has already computed it, continuously, based on the field's declared HTML constraints.
2checkValidity(): Silent Constraint Testing
element.checkValidity() (available on individual fields and on the <form> element itself, checking all its fields at once) evaluates the current constraint state and returns a plain boolean ā true if valid, false if not ā firing an invalid event on any field that fails, but displaying zero visible UI on its own.
This silence is precisely what makes it useful as a building block: a developer can call checkValidity() to gate some custom logic (like disabling a submit button, or triggering a fully custom error-message rendering system) without the browser's own UI interfering or appearing unexpectedly.
3reportValidity(): The Visible Counterpart
element.reportValidity() runs the identical underlying check as checkValidity(), but additionally displays the browser's native validation UI ā the same small bubble pointing at an invalid field with a message like 'Please fill out this field' that automatically appears when a form is submitted with invalid data.
Calling it explicitly, rather than relying solely on automatic submission-time validation, lets a developer trigger native validation feedback at custom moments ā for instance, re-validating and showing feedback for just one field the moment a user blurs out of it, rather than waiting for full form submission.
4Step-by-Step Breakdown
Validation The Browser Already Knows How To Do. Long before reaching for a JavaScript validation library, browsers already ship a complete, native Constraint Validation API ā every form control carries built-in validity state, and the browser can check and report it without a single line of custom validation logic.
Every Form Control Has A validity Object. Every form control element exposes a read-only .validity property ā a ValidityState object with boolean flags like valueMissing, typeMismatch, and patternMismatch, letting JavaScript inspect exactly why a field is currently invalid without writing any validation logic itself.
The validity Object. What does checking input.validity.typeMismatch tell you for an <input type="email">?
- āWhether the field is currently empty
- āWhether the entered value doesn't match the expected email format
- āWhether the field is currently disabled
checkValidity() Tests Without Showing UI. element.checkValidity() (or form.checkValidity() for the whole form) returns true/false based on current constraint state, firing an 'invalid' event on failure ā but doesn't display any browser UI, giving JavaScript full control over what happens next.
checkValidity() Behavior. Does calling form.checkValidity() automatically display the browser's native validation error bubbles to the user?
- āYes, it always displays the native error UI immediately
- āNo, it silently returns true/false without showing any UI
- āIt varies unpredictably by browser with no consistent behavior
reportValidity() Shows The Browser's Native UI. element.reportValidity() performs the same check as checkValidity(), but additionally displays the browser's built-in validation message bubble pointing at the invalid field ā the same UI that fires automatically on form submission, now triggerable on demand.
reportValidity() vs checkValidity(). What's the key difference between reportValidity() and checkValidity()?
- āThey're functionally identical with no real difference
- āreportValidity() additionally displays the browser's native validation error UI
- ācheckValidity() is the one that shows UI, not reportValidity()
Validation API Understood. You now understand the browser's built-in Constraint Validation API: every field's validity object, the silent checkValidity() test, and the UI-displaying reportValidity() method ā the foundation this entire Modern Forms module builds on before reaching for any JavaScript validation library.
Add A Visible Error Message Slot. The Constraint Validation API can show a custom message here when the required input is invalid.
Level Up š
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Native Validation UI Is Already Accessible By Default
The browser's built-in reportValidity() error bubbles are announced correctly to screen readers and receive focus automatically, a baseline of accessible behavior that hand-rolled custom validation UI must deliberately replicate.
SEO Implications
- 1
Native Validation Reduces JavaScript Payload Compared To A Full Validation Library
Relying on the built-in Constraint Validation API for common cases avoids shipping an entire validation library's bundle weight, indirectly supporting faster page load and better Core Web Vitals scores.
Best Practices
Check What The Native Constraint Validation API Already Covers Before Reaching For A Validation Library
Many common validation needs (required fields, email format, length limits, numeric ranges) are already fully handled natively, at zero JavaScript bundle cost, before any custom code is written.
Use checkValidity() For Silent Logic Gating And reportValidity() When You Want Native Error UI To Appear
Choosing the right method for the situation avoids either accidentally suppressing helpful native feedback or triggering unwanted UI at the wrong moment.
Frequent Bugs
A form's submit handler runs custom logic even though a required field is empty.
Call form.checkValidity() (or reportValidity() for visible feedback) at the start of the submit handler and return early if it's false.
A team builds a fully custom JavaScript validation system without realizing basic checks were already available natively.
Audit which validations the native Constraint Validation API already covers, and reserve custom JS validation for genuinely custom business rules it can't express.
Real-World Examples
Field-Level Validation On Blur
Providing immediate native validation feedback as a user moves between form fields, rather than waiting for full submission.
form.querySelectorAll('input').forEach(input => {
input.addEventListener('blur', () => input.reportValidity());
});