HTML Form Validation

โ–ถ Try It Yourself

HTML Form Validation

1. Introduction

HTML5 built-in form validation lets browsers enforce rules on user input before any data is sent to the server โ€” with zero JavaScript required for basic cases. Attributes like required, minlength, pattern, and min/max define constraints, while the browser handles displaying error messages. This lesson covers all native validation attributes, how they work together, and how to write accessible custom error messages.

2. Concept

Validation Attributes Overview

Attribute Applies To Validates
required All inputs Field must not be empty
minlength / maxlength text, email, password, textarea Character count
min / max number, date, range, time Numeric / date range
pattern text, email, tel, url, search Regular expression match
type="email" input Must contain @ and domain
type="url" input Must be valid URL with scheme
Note: Browser-native validation is a first line of defence, not a complete security solution. Always validate and sanitise data on the server as well โ€” client-side validation can be bypassed by anyone with browser developer tools.
Tip: Add aria-describedby on an input pointing to a hint paragraph. When validation fails, update that paragraph’s text with the error message so screen readers announce it.
Warning: Do not use novalidate on a form without implementing JavaScript-based validation as a replacement. Without either, users can submit invalid or empty data to your server.

3. Basic Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Form Validation Demo</title>
  </head>
  <body>
    <form action="/signup" method="post">

      <!-- required: must not be empty -->
      <label for="v-name">Full Name *</label>
      <input type="text" id="v-name" name="name"
        required
        minlength="2"
        maxlength="60"
      >

      <!-- email type + required -->
      <label for="v-email">Email *</label>
      <input type="email" id="v-email" name="email" required>

      <!-- pattern: UK postcode -->
      <label for="postcode">UK Postcode</label>
      <input
        type="text"
        id="postcode"
        name="postcode"
        pattern="^[A-Z]{1,2}[0-9][0-9A-Z]?\s?[0-9][A-Z]{2}$"
        title="Enter a valid UK postcode, e.g. SW1A 1AA"
      >

      <!-- Number range -->
      <label for="v-age">Age (18โ€“100) *</label>
      <input type="number" id="v-age" name="age" min="18" max="100" required>

      <!-- Password with minlength -->
      <label for="v-pass">Password (min 8 chars) *</label>
      <input type="password" id="v-pass" name="password" minlength="8" required>

      <button type="submit">Sign Up</button>
    </form>
  </body>
</html>

4. How It Works

Step 1 โ€” required Prevents Empty Submission

When a form is submitted, the browser checks every required field. If any is empty, the browser focuses the first invalid field and displays a tooltip error bubble. The form is not submitted until all constraints pass.

Step 2 โ€” minlength and maxlength on Text

minlength="2" prevents submitting with fewer than 2 characters. The browser shows an error message. maxlength hard-limits typing rather than showing an error on submit.

Step 3 โ€” pattern with a Regular Expression

The pattern attribute takes a regex without surrounding slashes. It must match the entire value. The title attribute provides the error message text the browser displays when the pattern does not match.

Step 4 โ€” min and max on Number Inputs

min="18" max="100" constrains the accepted value range. The browser rejects values outside this range on submit. The native number spinner also respects these bounds.

5. Real-World Example

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Checkout โ€” Shipping Details</title>
  </head>
  <body>
    <h1>Shipping Information</h1>

    <form action="/checkout/shipping" method="post" novalidate id="shipping-form">

      <label for="s-name">Full Name</label>
      <input type="text" id="s-name" name="full_name"
        required minlength="2" maxlength="80"
        autocomplete="name"
        aria-required="true"
        aria-describedby="s-name-err"
      >
      <span id="s-name-err" role="alert" aria-live="polite"></span>

      <label for="s-address">Street Address</label>
      <input type="text" id="s-address" name="address"
        required minlength="5" autocomplete="street-address"
      >

      <label for="s-city">City</label>
      <input type="text" id="s-city" name="city"
        required autocomplete="address-level2"
      >

      <label for="s-postcode">Postcode</label>
      <input type="text" id="s-postcode" name="postcode"
        required
        pattern="^[A-Z]{1,2}[0-9][0-9A-Z]?\s?[0-9][A-Z]{2}$"
        title="Enter a valid UK postcode e.g. EC1A 1BB"
        autocomplete="postal-code"
      >

      <label for="s-phone">Phone Number</label>
      <input type="tel" id="s-phone" name="phone"
        required
        pattern="[+0-9\s\-]{7,20}"
        title="Phone number (digits, spaces, hyphens, optional +)"
        autocomplete="tel"
      >

      <button type="submit">Continue to Payment</button>
    </form>

    <script>
      const form = document.getElementById('shipping-form');
      form.addEventListener('submit', function(e) {
        const nameInput = document.getElementById('s-name');
        const errSpan   = document.getElementById('s-name-err');
        if (!nameInput.validity.valid) {
          e.preventDefault();
          errSpan.textContent = 'Please enter your full name (at least 2 characters).';
        } else {
          errSpan.textContent = '';
        }
      });
    </script>
  </body>
</html>

6. Common Mistakes

Relying solely on client-side validation

<input type="email" required> <!-- only HTML validation -->

Validate on both client AND server; never trust client data alone

<!-- HTML validates format first; server must also validate/sanitise -->
<input type="email" required>

Missing title attribute with pattern

<input pattern="[A-Z]{3}">

Always add title to explain the expected pattern

<input pattern="[A-Z]{3}" title="Enter exactly 3 uppercase letters">

7. Try It Yourself

▶ Try It Yourself

8. Quick Reference

Attribute Valid On Error Condition
required Most inputs Empty value on submit
minlength text, email, password, textarea Value shorter than n chars
maxlength text, email, password, textarea Prevents typing beyond n
min number, date, time, range Value below minimum
max number, date, time, range Value above maximum
pattern text, tel, url, email, search Value doesn’t match regex
title All Error tooltip text for pattern failures

9. Quiz

🧠 Test Yourself

Where should the human-readable explanation for a pattern attribute’s format be placed?





โ–ถ Try It Yourself