Built-in Form Validation
HTML validation attributes describe constraints directly in the markup. The browser enforces them on submit and exposes them through CSS pseudo-classes and the Constraint Validation API, so you can style invalid fields and read error reasons in JavaScript without reinventing the logic.
What it is
HTML provides a set of attributes that declare constraints on form field values. required means the field must not be empty. minlength and maxlength bound the length of text. min and max bound numeric values. pattern takes a regular expression the value must match (the pattern is implicitly anchored to the full value, so [0-9]{5} matches exactly five digits with no extra characters). type="email" and type="url" validate format as well as collecting input. These attributes are checked by the browser automatically when the user submits the form.
The Constraint Validation API exposes the validation state of any input through its validity property, a ValidityState object with boolean flags: valueMissing (required field is empty), typeMismatch (value does not match the type's format), patternMismatch (value does not match pattern), tooShort/tooLong, rangeUnderflow/rangeOverflow, and valid (all constraints pass). input.checkValidity() returns a boolean and fires the invalid event on failure. input.reportValidity() does the same and also shows the browser's built-in tooltip. input.setCustomValidity(message) marks the field invalid with a custom message; call it with an empty string to clear the custom error.
Why it matters
Built-in validation runs before any JavaScript, including your own. A form with required on every field prevents submission with empty values even if JavaScript is blocked or has not loaded yet. This is not a replacement for server-side validation (never trust the client), but it is a useful first line of feedback that costs no code to implement.
The CSS pseudo-classes :valid and :invalid let you style fields based on their constraint state. A green border on a valid email field and a red border on an invalid one are achievable with two CSS rules and zero JavaScript. The pattern attribute used with :invalid can show error styling as the user types, giving immediate feedback without a submit attempt.
How it works
Add validation attributes to the relevant inputs. The browser checks them on submit and, if any field is invalid, prevents submission, focuses the first invalid field, and shows a localised tooltip with the reason. You can customise which message appears by calling setCustomValidity() in an input event handler before the browser validation runs.
To style fields based on validity, use :valid and :invalid in CSS. For a better user experience, use :user-invalid and :user-valid (supported in all modern browsers), which only apply after the user has interacted with the field. The problem with plain :invalid is that it fires on page load: an empty required field is technically invalid from the moment the page renders, so it turns red before the user has had a chance to type anything.
Add novalidate to the <form> element to opt out of browser built-in validation entirely. You might do this when you are implementing custom validation UI with JavaScript, or when using a form library that handles its own error messages. The Constraint Validation API still works on the individual inputs; novalidate only suppresses the automatic check on submit and the browser tooltip.
Try it
Type into each field and watch the border flip as constraints are met or broken. Hit the submit button to trigger the browser's built-in validation UI.
<!-- validation attributes --><input required minlength="2" name="name" /><input type="email" required name="email" /><input pattern="[0-9]{5}" required name="zip" />/* CSS */input:invalid { /* fires on page load! */}input:user-invalid { /* only after interaction */}/* API */input.validity.validinput.validity.valueMissinginput.validity.typeMismatchinput.validity.patternMismatchinput.reportValidity()
validity flags now
Check yourself
Pick an answer to lock it in, then read why. Getting one wrong is part of how it sticks.
Remember this
patternis implicitly anchored: the entire value must match, not just a substring.:invalidfires on page load for empty required fields; use:user-invalidto show errors only after the user has interacted.setCustomValidity(message)marks a field invalid with a custom message; pass an empty string to clear it.novalidateon the form suppresses built-in submit validation but does not affect the Constraint Validation API on individual inputs.
Done with this concept?
Mark it complete to track your progress. No login needed.