HTML Form Validation

Check user input before it's sent with built-in validation attributes such as required, minlength, pattern, min and max, style valid and invalid fields, and use form attributes like action, method and autocomplete.

Lesson 22 of 44Intermediate15 min read

Users make mistakes: they leave fields empty, mistype an email address, enter a phone number with letters in it or choose a date in the past. Catching those mistakes before a form is sent saves everyone time. HTML can do much of this checking by itself, with no JavaScript, using validation attributes.

When a field has a rule such as required or minlength="8", the browser refuses to submit the form until the rule is met, shows a message next to the first problem and moves focus to it. Input types help too: a type="email" field already checks for an @, and type="number" rejects text. You can then style valid and invalid fields with CSS so users see problems clearly.

Browser validation improves the experience, but it is not security. Anyone can switch it off or send data directly to your server, so the server must always validate again. In this lesson you'll learn the validation attributes, the main form attributes such as action, method and autocomplete, and how to write helpful error hints.

Validation attributes

AttributeRuleExample
requiredField can't be empty<input required>
minlength, maxlengthLength of textminlength="8"
min, maxSmallest and largest number or datemin="1" max="10"
stepAllowed incrementsstep="0.01" for prices
patternText must match a regular expressionpattern="[A-Z]{2}[0-9]{4}"
typeFormat such as email, url or numbertype="email"

Add a title or a hint below the field to explain a pattern, because the default error message can't describe your format.

Form attributes

  • action is the URL that receives the data; method is get (data in the URL, good for searches) or post (data in the request body, for anything that changes something, or contains personal data).
  • autocomplete helps browsers fill in saved details: autocomplete="email", "name", "street-address", "current-password", "new-password".
  • novalidate on the form turns off browser validation, used when JavaScript shows its own messages.
  • readonly shows a value that can't be edited but is still sent; disabled fields are neither editable nor sent.
  • autofocus places the cursor in a field when the page loads; use it sparingly.

Styling valid and invalid fields

CSS can react to validation:

CSS
input:user-invalid { border-color: crimson; }
input:user-valid { border-color: seagreen; }

:user-invalid only applies after the user has interacted with the field, so a fresh form isn't covered in red. Older code uses :invalid, which matches immediately. Pair colour with text, such as an error message, because colour alone isn't enough for everyone.

HTML Form Validation Syntax

Validation syntax

<form action="/register" method="post">
  <input type="email" name="email" required autocomplete="email">
  <input type="password" name="password" required minlength="8" autocomplete="new-password">
  <input type="number" name="age" min="13" max="120">
  <input type="text" name="postcode" pattern="[A-Za-z0-9 ]{5,8}" title="5 to 8 letters and numbers">
  <input type="number" name="price" step="0.01" min="0">
  <button type="submit">Register</button>
</form>

HTML Form Validation Summary

  • required, minlength, maxlength, min, max, step and pattern add built-in validation.
  • The browser blocks submission and highlights the first invalid field.
  • action and method decide where and how data is sent; autocomplete speeds up filling in.
  • Style feedback with :user-invalid and :user-valid, plus clear text hints.
  • Client-side validation is for convenience; always validate again on the server.

HTML Form Validation Examples

Each example runs in the page. Edit the code and press Run to see what changes.

Example 1

A registration form with validation

Press Register with empty or invalid fields to see the browser's checks.

<form action="#" method="post">
  <p>
    <label for="em">Email</label><br>
    <input id="em" name="email" type="email" required autocomplete="email">
  </p>
  <p>
    <label for="pw">Password</label><br>
    <input id="pw" name="password" type="password" required minlength="8" autocomplete="new-password" aria-describedby="pw-hint">
    <br><small id="pw-hint">At least 8 characters.</small>
  </p>
  <p>
    <label for="age">Age</label><br>
    <input id="age" name="age" type="number" min="13" max="120">
  </p>
  <button type="submit">Register</button>
</form>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 4type="email" and required together check that a valid address was entered.
  2. Line 8minlength enforces at least 8 characters, and aria-describedby links the hint to the field.
  3. Line 9The hint is visible before the user types.
  4. Line 13Ages outside 13 to 120 are rejected.
Example 2

Patterns with helpful hints

<form action="#">
  <label for="code">Discount code</label><br>
  <input id="code" name="code" pattern="[A-Z]{4}[0-9]{2}" title="4 capital letters then 2 numbers, like SAVE10" placeholder="SAVE10" required>
  <p><small>Format: 4 capital letters then 2 numbers.</small></p>
  <label for="qty">Quantity (1 to 5)</label><br>
  <input id="qty" name="qty" type="number" min="1" max="5" step="1" value="1">
  <p><button type="submit">Apply</button></p>
</form>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3pattern requires exactly four capital letters followed by two digits.
  2. Line 3title is added to the browser's error message to explain the format.
  3. Line 6min, max and step restrict quantity to whole numbers from 1 to 5.
Example 3

Styling feedback after typing

<style>
  input { padding: 8px; border: 2px solid #9ca3af; border-radius: 6px; }
  input:user-invalid { border-color: #dc2626; }
  input:user-valid { border-color: #16a34a; }
  input:user-invalid + .msg { display: block; }
  .msg { display: none; color: #b91c1c; font-size: 0.9em; }
</style>
<form>
  <label for="mail">Email</label><br>
  <input id="mail" type="email" required>
  <span class="msg">Please enter an email address like name@example.com.</span>
</form>
ResultEdit the code, then press Run or Ctrl+Enter
Line-by-line explanation
  1. Line 3Red border once the user has typed something invalid and left the field.
  2. Line 4Green border when the value is valid.
  3. Lines 5 to 6The written message appears only when the field is invalid.

Common HTML Form Validation Mistakes

Trusting browser validation on the server

Don't
<!-- "The form has required, so the server doesn't need to check" -->
<input name="email" type="email" required>
Do
<input name="email" type="email" required>
<!-- and the server validates the email again before saving -->

Validation in the browser can be bypassed easily.

A pattern with no explanation

Don't
<input name="ref" pattern="[0-9]{6}">
Do
<label for="ref">Order reference (6 digits)</label>
<input id="ref" name="ref" pattern="[0-9]{6}" title="6 digits, for example 104233">

Otherwise users only see "Please match the requested format".

Sending passwords with GET

Don't
<form action="/login" method="get">
Do
<form action="/login" method="post">

GET puts the data in the URL, where it's saved in history and server logs.

HTML Form Validation in Real Projects

Validation in practice

Registration and checkout forms on most sites combine HTML attributes for instant feedback with JavaScript for custom messages and server checks for security. Password managers rely on correct autocomplete values, and payment providers use patterns and lengths to catch typos in card details before contacting the bank.

HTML Form Validation Exercises

Answer each one and check it instantly. If you get stuck, open the hint before the answer.

Fill in the blankseasy

Make the field mandatory.

<input name="name" >
Multiple choiceeasy

Which attribute sets the minimum number of characters?

Multiple choicemedium

Which method should a login form use?

Multiple choicemedium

What does pattern="[0-9]{5}" require?

Fix the bugmedium

Add validation so the form can't be sent empty: email is required and must be an email address, and the password needs at least 8 characters.

<form>
  <label for="e">Email</label>
  <input id="e" name="email" type="text">
  <label for="p">Password</label>
  <input id="p" name="password" type="password">
  <button type="submit">Sign in</button>
</form>
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Email is required with type email
  • Password is required
  • Password minlength is 8

HTML Form Validation Quiz

5 questions to check what you learned.

  1. What happens when you submit a form with an empty required field?

    • It's sent anyway
    • The browser blocks it and shows a message
    • The page reloads
    • The field is filled automatically
  2. Is HTML validation enough to protect your server?

    • Yes
    • Only with pattern
    • Only for passwords
    • No, the server must validate too
  3. What does autocomplete="new-password" help with?

    • Telling password managers to suggest a new strong password
    • Blocking autofill
    • Validating the password
    • Hiding the password
  4. What's the difference between :invalid and :user-invalid?

    • They're identical
    • :invalid is only for numbers
    • :user-invalid only applies after the user has interacted with the field
    • :user-invalid is a JavaScript method
  5. What does novalidate on a form do?

    • Removes all fields
    • Validates on the server
    • Turns off the browser's built-in validation, usually so JavaScript can handle it
    • Hides error messages forever

HTML Form Validation Challenge

A booking form

Build a form with:

  1. A required type="email" field with autocomplete="email"
  2. A type="number" field for guests with min="1" and max="8"
  3. A text field with pattern="[A-Z]{3}[0-9]{3}" and a title explaining the format
  4. method="post" on the form
ResultEdit the code, then press Run or Ctrl+Enter
Checks
  • Required email with autocomplete
  • Guests between 1 and 8
  • Pattern field with a title
  • Form uses POST