HTMLForm Validation (required, pattern)

Form Validation

Long before JavaScript frameworks had validation libraries, HTML already had a built-in system for it. A handful of attributes — required, pattern, minlength/maxlength, min/max — tell the browser what a valid value looks like, and the browser blocks submission and shows a native error message when a field doesn't qualify. It's not a replacement for server-side validation, but it catches the vast majority of mistakes for free, with no JavaScript at all.

required

The simplest validation attribute: the field must have a value before the form can submit.

required.html

HTML
<form>
  <label for="email">Email</label>
  <input type="email" id="email" name="email" required />

  <button type="submit">Sign up</button>
</form>

Try submitting this form empty and the browser shows a native tooltip like "Please fill out this field" and refuses to submit — no JavaScript required.

pattern — Regular Expression Matching

pattern takes a JavaScript-flavored regular expression (without the surrounding slashes) that the field's value must fully match.

pattern.html

HTML
<label for="zip">US ZIP code</label>
<input
  type="text"
  id="zip"
  name="zip"
  pattern="[0-9]{5}(-[0-9]{4})?"
  title="Enter a 5-digit ZIP code, optionally followed by -1234"
  required
/>
Pair pattern with title
The title attribute's text is shown as part of the browser's native validation message when the pattern doesn't match — always include one, or the visitor only sees "match the requested format" with no clue what that format is.
minlength / maxlength

These constrain the number of characters typed. Unlike maxlength, which also stops the browser from letting the user type past the limit, minlength is purely a validation check on submit.

minlength-maxlength.html

HTML
<label for="password">Password</label>
<input
  type="password"
  id="password"
  name="password"
  minlength="8"
  maxlength="64"
  required
/>
min / max for Numbers

For number, range, and date/time input types, min and max set the acceptable bounds. A step attribute can further restrict the value to a multiple of a given increment.

min-max.html

HTML
<label for="quantity">Quantity (1–10)</label>
<input type="number" id="quantity" name="quantity" min="1" max="10" step="1" value="1" />
Common Validation Attributes at a Glance

Attribute

Applies to

Checks

required

Most input types, <select>, <textarea>

A value is present

pattern

Text-like inputs

Value matches a regular expression

minlength / maxlength

Text-like inputs, <textarea>

Character count bounds

min / max

number, range, date/time types

Numeric or date value bounds

step

number, range, date/time types

Value is a valid increment from min

type="email" / type="url"

Those specific input types

Value matches the expected format

The Browser's Native Validation UI

When a form with invalid fields is submitted, the browser automatically:

  • Cancels the submission before it reaches the server.

  • Focuses the first invalid field.

  • Shows a small native tooltip explaining the problem (wording and appearance differ per browser).

Please fill out this field.
Please match the requested format: Enter a 5-digit ZIP code, optionally followed by -1234
Native messages are not stylable
You cannot restyle the browser's built-in validation tooltip with CSS — its appearance is controlled entirely by the browser/OS. If you need fully custom-styled error messages, you'll pair this with the Constraint Validation API and your own markup (covered in the next tutorial).
Styling With :valid and :invalid

CSS pseudo-classes let you style a field based on its current validity state, without any JavaScript.

valid-invalid.css

CSS
input:invalid {
  border-color: #d64545;
}

input:valid {
  border-color: #2e7d32;
}

/* Avoid shaming the user before they've typed anything */
input:placeholder-shown:invalid {
  border-color: initial;
}
Don't shame empty fields
By default, a required-but-empty field matches :invalid the instant the page loads, before the user has done anything wrong. The :placeholder-shown:invalid combinator above is a common trick to suppress the "invalid" styling until the field has actually been touched and left in a bad state — even better is toggling styles in response to the blur or submit event with JavaScript.
A Complete Example

validation-example.html

HTML
<form novalidate id="signup-form">
  <label for="username">Username</label>
  <input
    type="text"
    id="username"
    name="username"
    pattern="[a-zA-Z0-9_]{3,16}"
    title="3-16 characters: letters, numbers, underscore"
    required
  />

  <label for="email">Email</label>
  <input type="email" id="email" name="email" required />

  <label for="age">Age</label>
  <input type="number" id="age" name="age" min="13" max="120" required />

  <button type="submit">Create account</button>
</form>
novalidate for progressive enhancement
Adding novalidate to the <form> turns off the browser's automatic validation UI so you can drive it entirely through JavaScript instead — useful when you want fully custom error messages while still keeping the same HTML validation attributes as your source of truth (see the Constraint Validation API tutorial).
Client-side is not enough
Every one of these attributes can be bypassed — a visitor can edit the DOM, disable JavaScript, or send a request directly with a tool like curl. HTML validation is a UX convenience, not a security boundary. Always re-validate on the server.