HTMLBeginner

HTML Form Validation: required, pattern, min, max Explained

Learn HTML's built-in form validation: required, pattern with regex, minlength/maxlength, min/max/step, custom messages, novalidate, and its real limits.

All HTML lessons

What you will learn

Before a single line of JavaScript, HTML already knows how to stop a visitor from submitting an obviously broken form — a missing required field, a password that’s too short, an email that doesn’t look like one. In this lesson you will learn required, pattern (regular expressions), minlength/maxlength, min/max/step, how to write a custom error message, novalidate, and — importantly — the real limits of validation that happens only in the browser.

required: the field cannot be empty

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

required is a boolean attribute (no value needed). If the visitor tries to submit the form with this field empty, the browser blocks the submission and shows a small built-in error bubble, usually pointing right at the field.

<select name="country" required>
  <option value="" disabled selected>Choose your country</option>
  <option value="in">India</option>
</select>

<textarea name="feedback" required></textarea>

<input type="checkbox" name="terms" required> I agree to the terms

required works on <input>, <select> and <textarea> alike, and on a checkbox it specifically means “this box must be checked” (useful for a mandatory “I agree to the terms” checkbox).

minlength and maxlength: text length limits

<label for="username">Username</label>
<input type="text" id="username" name="username" minlength="3" maxlength="15">
  • minlength — the shortest allowed input. The browser blocks submission if the visitor types fewer characters (it does not stop them from typing a short value while still typing — the check happens on submit).
  • maxlength — the longest allowed input. Unlike minlength, this one actively prevents typing any further once the limit is reached — the browser simply won’t accept another keystroke.

Both work on <input> (text-like types) and <textarea>.

min, max and step: numeric and date limits

You met these briefly in the input types lesson — here’s their validation role specifically:

<input type="number" name="age" min="13" max="100">
<input type="date" name="eventDate" min="2026-01-01" max="2026-12-31">
<input type="number" name="quantity" min="1" max="10" step="1">
  • min / max set the allowed numeric or date range. A value outside it blocks submission.
  • step sets what counts as a valid increment. With step="1", entering 4.5 is invalid; the up/down arrows (or a date picker’s day-by-day movement) respect this too.

pattern: matching a custom format with regex

pattern accepts a regular expression — a compact way of describing “text that follows this exact shape.” It’s the most powerful, and most misused, validation attribute, so it’s worth a careful look.

<label for="pin">PIN code</label>
<input type="text" id="pin" name="pin" pattern="[0-9]{6}" title="Enter a 6-digit PIN code">

Read [0-9]{6} as: “exactly 6 characters, each one a digit from 0–9.” A visitor typing letters, or fewer/more than 6 digits, gets blocked.

A few more genuinely useful patterns:

<!-- Indian mobile number: optional +91, then 10 digits starting 6-9 -->
<input type="tel" name="phone" pattern="(\+91)?[6-9][0-9]{9}" title="Enter a valid 10-digit mobile number">

<!-- Letters, numbers and underscores only, for a username -->
<input type="text" name="username" pattern="[a-zA-Z0-9_]+" title="Letters, numbers and underscores only">

<!-- At least one letter and one number (a simple password strength rule) -->
<input type="password" name="password" pattern="(?=.*[A-Za-z])(?=.*\d).+" title="Must include at least one letter and one number">

You don’t need to become a regex expert to use pattern productively as a beginner — a full regular expressions lesson comes later in the JavaScript section of this course. For now, know that [0-9] means “a digit,” [a-zA-Z] means “a letter,” + means “one or more,” {6} means “exactly six,” and that plenty of ready-made, well-tested patterns for common cases (phone numbers, postal codes, etc.) can be found online rather than written from scratch.

title pairs with pattern to explain the error

Notice every pattern example above also has a title. When a pattern fails, many browsers show the title text as (or as part of) the error message — without it, the visitor just sees a generic “Please match the requested format,” with no idea what the actual expected format is. Always pair pattern with a title explaining what’s expected.

type itself is validation too

Don’t forget: choosing the right type (from the input types lesson) already validates for you. type="email" checks for a roughly correct email shape; type="url" checks for a valid URL; type="number" rejects non-numeric text entirely. You often don’t need pattern at all if the right type already covers your case.

Styling valid and invalid fields with CSS

Two CSS pseudo-classes let you visually respond to a field’s validity, live, with no JavaScript:

input:invalid {
  border: 2px solid tomato;
}

input:valid {
  border: 2px solid seagreen;
}
<input type="email" name="email" required>

As the visitor types, the browser continuously evaluates the field against its type, required, pattern and other rules, and applies :valid or :invalid accordingly — you’ll cover this kind of selector properly in the CSS course, but it’s worth knowing HTML validation and CSS styling connect directly like this.

novalidate: turning off built-in validation

<form novalidate>
  <input type="email" name="email" required>
  <button type="submit">Send</button>
</form>

novalidate on the <form> element disables all of HTML’s built-in validation checks for that form. This is used when you want to build your own custom validation with JavaScript (perhaps with nicer-looking error messages, or validation logic too complex for pattern alone) instead of relying on the browser’s default behaviour. As a beginner, you generally won’t need this yet — it’s here so you recognise it later when you see it.

The most important limit: this is not a security feature

This is the detail that separates a beginner from someone who understands forms properly: everything in this lesson runs entirely inside the visitor’s own browser, before the data is even sent.

That means it can always be bypassed — by disabling JavaScript, by using browser developer tools to remove a required attribute, or simply by sending a request directly to your server with tools that skip the browser (and its HTML) entirely. HTML validation is a usability feature: it gives visitors instant, friendly feedback without waiting for a full round trip to the server. It is not a security boundary.

The rule every backend developer learns the hard way: never trust data just because the HTML form that (supposedly) sent it had required, pattern or maxlength on it. Always re-validate everything on the server, no matter how thoroughly the client-side HTML validates it. You’ll see exactly why, and how, once you build a real backend later in this course.

A complete example

<form>
  <label for="username">Username</label>
  <input
    type="text"
    id="username"
    name="username"
    required
    minlength="3"
    maxlength="15"
    pattern="[a-zA-Z0-9_]+"
    title="3-15 characters: letters, numbers and underscores only"
  >

  <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" required min="13" max="100">

  <label><input type="checkbox" name="terms" required> I agree to the terms</label>

  <button type="submit">Create account</button>
</form>

Common mistakes

  • Writing a pattern without a title. The visitor sees a generic error with no clue what format is actually expected.
  • Relying on HTML validation as the only line of defence. It can always be bypassed; the server must re-validate everything independently.
  • Using pattern for something the right type already handles, like re-inventing an email check that type="email" already gives you for free.
  • Forgetting that minlength doesn’t block typing, only submission — unlike maxlength, which does stop further typing once reached.
  • Setting min/max on the wrong type — these only work on number, range and date/time input types, not on plain text.
  • Adding novalidate without actually building replacement validation logic, silently removing the browser’s safety net for no benefit.

Interview-style questions

Why is required alone not “real” validation from a security standpoint? Because it’s enforced entirely in the browser and can be bypassed (disabling JavaScript, editing dev tools, or sending requests directly) — a server must independently validate all incoming data regardless of what the HTML form specified.

What’s the difference between minlength and maxlength in terms of when they act? maxlength actively prevents typing beyond the limit as the visitor types. minlength only checks the total length when the form is submitted — it doesn’t stop the visitor from having fewer characters while still typing.

Why should pattern usually be paired with title? Because many browsers display the title text as the validation error message when the pattern doesn’t match, giving the visitor a clear explanation instead of a generic error.

What does novalidate do, and when would you use it? It disables the browser’s built-in validation for the whole form — used when you’re replacing it with custom JavaScript validation instead.

Practice

  1. Use the Practice in Editor button. Try submitting the form empty, then with a 2-character username, then with symbols in the username, and read each error message the browser shows.
  2. Add required to a checkbox for “I agree to the terms” and test that the form won’t submit until it’s checked.
  3. Write a pattern (with a matching title) for a 6-digit Indian PIN code field.
  4. Explain in your own words why a form with required, pattern and maxlength set correctly still needs server-side validation.

Recap

  • required blocks submission if a field is empty (or a checkbox unchecked); works on <input>, <select> and <textarea>.
  • minlength/maxlength bound text length; maxlength actively blocks extra typing, minlength only checks on submit.
  • min/max/step bound and constrain numeric and date/time values.
  • pattern matches a custom format with a regular expression — always pair it with title for a clear error message.
  • :valid/:invalid in CSS let you style fields based on their current validity, live.
  • HTML validation is a usability convenience, not a security control — always validate again on the server.