Quiz

How do you validate form elements using the Constraint Validation API?

Topics
Web APIsJavaScript

TL;DR

Put basic rules in HTML (required, type, min, max, minlength, maxlength, and pattern), then use the Constraint Validation API for custom relationships and feedback. checkValidity() returns a boolean and fires invalid on invalid controls; reportValidity() also asks the browser to show its validation UI. A nonempty setCustomValidity() message keeps a control invalid, so clear it with setCustomValidity('') as soon as the value becomes valid.

Browser validation improves user experience, not security. Repeat all validation on the server because requests can bypass the form.


Key properties and methods

  • element.validity is a ValidityState with flags such as valueMissing, typeMismatch, rangeUnderflow, and patternMismatch.
  • element.validationMessage contains the browser or custom message for the current failure.
  • element.checkValidity() checks constraints and returns false when invalid.
  • element.reportValidity() performs the check and displays the browser's validation feedback when possible.
  • element.setCustomValidity(message) sets an application-specific failure. Pass an empty string to clear it.
  • form.noValidate or the novalidate attribute disables interactive validation for that form, which is useful only when the application intentionally renders all feedback itself.

Practical example: matching password fields

HTML constraints handle each field, while JavaScript handles the relationship between them:

<form id="signup-form">
<label>
Email
<input name="email" type="email" required />
</label>
<label>
Password
<input
id="password"
name="password"
type="password"
minlength="12"
required />
</label>
<label>
Confirm password
<input id="confirm-password" type="password" required />
</label>
<button>Sign up</button>
</form>
const form = document.querySelector('#signup-form');
const password = document.querySelector('#password');
const confirmation = document.querySelector('#confirm-password');
function validateConfirmation() {
confirmation.setCustomValidity(
confirmation.value === password.value ? '' : 'Passwords do not match',
);
}
form.addEventListener('input', validateConfirmation);
form.addEventListener('submit', (event) => {
// Native interactive validation has already succeeded if this event fires.
event.preventDefault();
submitSignupForm(new FormData(form));
});

The message is recalculated on every user edit. Code that changes either value programmatically should also call validateConfirmation(). A common bug is to call setCustomValidity('Passwords do not match') once and never clear it, leaving the control permanently invalid.

For a normal submit button, browsers run interactive constraint validation before firing submit; if a control is invalid, the submit event does not fire. Call form.reportValidity() when application code initiates a custom submission attempt and needs the browser to display validation feedback.

Validation and accessible feedback

Native controls and messages are a useful baseline. If you render custom messages, associate each message with its control, expose the invalid state (for example with aria-invalid), and move focus or provide a summary when submission fails. Do not rely on color alone.

Some controls and constraints have special rules. For example, certain values set programmatically are not checked by every constraint in the same way as user input. Test the actual form behavior in supported browsers and always keep server validation authoritative.

Further reading

Exercises

Check your understanding
Beta
Check your understanding Exercise 1 of 2
Check your understanding Exercise 1 of 2

A password-confirmation field previously called setCustomValidity("Passwords differ"). The values now match, but reportValidity() still marks the field invalid. What must the code do?