HTML Form Validation Attributes

required, pattern, min, max, step and the Constraint Validation API in one place.

Reference for HTML5 form validation attributes — required, pattern, min, max, minlength, step — plus the Constraint Validation API methods and ValidityState flags, with a live pattern tester. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

How does the pattern attribute work?

pattern holds a JavaScript regular expression that the entire value must match — it is implicitly anchored, so the regex must match the whole string. It applies to text, search, url, tel, email and password inputs and sets the patternMismatch flag when it fails.

Native validation without JavaScript

HTML5 form validation lets the browser enforce rules declaratively through attributes, exposing the result via the Constraint Validation API. This reference covers every validation attribute, the ValidityState flag it sets, and the API methods — plus a live tester for the pattern attribute.

The complete set of validation attributes

AttributeApplies toValidityState flag
requiredAll except hidden, range, color, submitvalueMissing
patterntext, search, url, tel, email, passwordpatternMismatch
minnumber, range, date, month, week, time, datetime-localrangeUnderflow
maxSame as minrangeOverflow
minlengthtext, search, url, tel, email, password, textareatooShort
maxlengthSame as minlengthtooLong
stepnumber, range, and temporal typesstepMismatch
type itselfNumeric and email typestypeMismatch

The valid flag is only true when all other flags are false and the control is not suffering a custom validity message.

How it works

Validation attributes constrain a control; on submit (or via a script call) the browser checks each constraint and sets the matching ValidityState flag:

<input type="text" required minlength="3" maxlength="20"
       pattern="[a-z0-9_]+" title="lowercase, digits, underscore">
const input = form.elements.username;
if (!input.checkValidity()) {
  console.log(input.validity); // { patternMismatch: true, ... }
}
input.setCustomValidity(taken ? "Username is taken" : "");
form.reportValidity(); // shows the bubble on the first invalid field

The pattern regex is implicitly anchored to the whole value (^(?:...)$), so it must match the entire string, not a substring.

The Constraint Validation API

Three methods let you drive validation from JavaScript:

  • checkValidity() — returns true or false and fires an invalid event on failure, but shows no UI.
  • reportValidity() — same as checkValidity() but additionally shows the browser’s native validation bubble on the first failing field and focuses it.
  • setCustomValidity(message) — injects a custom error message into ValidityState.customError. Pass an empty string to clear the custom error and mark the field valid again.

Called on the <form> element, checkValidity() and reportValidity() validate every control in the form.

Practical example — a username field

<form id="signup">
  <label>
    Username
    <input
      id="uname"
      type="text"
      required
      minlength="3"
      maxlength="20"
      pattern="[a-z0-9_]+"
      title="3–20 lowercase letters, digits or underscores"
      autocomplete="username">
  </label>
  <p id="uname-error" role="alert" hidden></p>
  <button type="submit">Register</button>
</form>
const field = document.getElementById('uname');
const errorEl = document.getElementById('uname-error');

field.addEventListener('blur', () => {
  if (!field.validity.valid) {
    errorEl.textContent = field.validationMessage;
    errorEl.hidden = false;
  } else {
    errorEl.hidden = true;
  }
});

Key gotchas

  • pattern only fires on non-empty values — always pair it with required if you also want to forbid blanks.
  • Always add title alongside pattern; the browser shows it in the native error bubble as the reason.
  • min/max on date inputs use ISO format (YYYY-MM-DD), not localised display strings.
  • step="5" on a number input rejects 7 because 7 is not a multiple of step from the min (or 0); use step="any" to allow arbitrary decimals.
  • novalidate on the <form> or formnovalidate on a submit button completely bypasses native checks — useful for save-draft buttons.
  • Style validated fields with :valid, :invalid, :required, and the newer :user-invalid (only applies after the user has interacted with the field, avoiding ugly red outlines on untouched forms).