Learning objectives
Use native validity constraints; inspect validity without confusing it with authorization; clear custom errors correctly and plan accessible feedback.
Prerequisites
Complete the form-control lessons and know basic JavaScript event handlers. This lesson includes JavaScript as progressive enhancement.
Let HTML express simple rules
Required, minlength, maxlength, min, max, step, and pattern cover many useful constraints. Type-specific rules handle supported email or URL syntax. Choose only rules that reflect the application’s actual requirements, and explain them before the person encounters an error. A rule that users cannot predict creates unnecessary trial and error.
The validity property exposes a set of flags describing problems such as valueMissing, typeMismatch, or rangeOverflow. CheckValidity returns whether applicable constraints are satisfied and fires invalid events for invalid controls. ReportValidity also asks the browser to present its validity feedback. The precise presentation and wording are browser-dependent.
Add custom rules without leaving stale state
SetCustomValidity stores a custom error string. A non-empty string makes the control invalid; an empty string clears that custom error. This is easy to misuse: if a script sets an error once and never clears it after correction, an apparently valid field can remain impossible to submit.
For a confirmation field, compare the values when the relevant inputs change, set a specific message when they differ, and clear it when they match. Do not wait until after a success message has already appeared. Avoid declaring success from a click handler attached only to a button, because forms can be submitted through other interaction paths. Listen for the form’s submit event when enhancing submission.
RequestSubmit behaves like an actual submission request, including validation and submitter behavior. The form submit method bypasses interactive validation and the submit event. Understand this distinction before using either in a production workflow. A method name that sounds convenient can accidentally skip the logic you rely on.
Design error recovery, not only error detection
A useful message identifies the problem and the correction: Enter a number from 1 to 6 is clearer than Invalid. Preserve the user’s other values after a failure. For a long form, provide an error summary linking to affected controls and place field-specific messages nearby. Use aria-invalid only when the field is actually being reported as invalid, and connect instructions or errors with aria-describedby where appropriate.
Every request can bypass client code. Server validation must independently check values, permissions, record ownership, business rules, and any security requirements. If the server rejects a value the client accepted, display that result in the same understandable recovery workflow. Client checks are a convenience, not proof that a transaction is safe.
Working example
<form id="booking">
<label for="seats">Seats (1 to 6)</label>
<input id="seats" name="seats" type="number" min="1" max="6" step="1" required>
<button type="submit">Check booking</button>
<p id="booking-status" role="status"></p>
</form>
Another example
<label for="reference">Booking reference</label>
<input id="reference" name="reference" pattern="[A-Z]{3}-[0-9]{4}" aria-describedby="reference-help">
<p id="reference-help">Use three uppercase letters, a hyphen, and four digits, for example ABC-1234.</p>
Expected output
The live example blocks an invalid ticket count with native feedback. A valid value produces a local message explaining that no booking was sent. The pattern example describes its format in visible text instead of expecting the browser error to teach the rule.
Common mistakes
Do not leave a non-empty custom validity message after correction. Do not disable native validation with novalidate unless the replacement is fully implemented and tested. Do not use a complex regular expression to claim that an email address exists.
Accessibility and browser notes
Error information must be available as text and associated with the affected control. Avoid shouting every keystroke through an assertive live region. Give the person time to finish typing and test both initial errors and corrected values using keyboard-only navigation.
Practice
Write a JavaScript rule for a confirmation input that reports a mismatch and clears the message after the values agree.
Review the solution and reasoning
const password = document.querySelector("#password");
const confirmation = document.querySelector("#confirmation");
function validateMatch() {
confirmation.setCustomValidity(confirmation.value === password.value ? "" : "The entries do not match.");
}
password.addEventListener("input", validateMatch);
confirmation.addEventListener("input", validateMatch);
The rule recomputes whenever either value changes and clears the custom error with an empty string. The receiving server must still validate the request. In a real password form, use appropriate autocomplete tokens and never log the entered values.