~/hackweb.dev
HTML Forms & Validation
Quiz
...

HTML Forms & Validation

beginner · updated Tue Sep 08 2026Contribute

Master forms, inputs, labels, and client-side validation.

HTML Forms & Validation

Forms collect user input — from simple text fields to complex multi-step workflows. They’re essential for login pages, search bars, contact forms, and more.

Basic Form Structure

Every form uses the <form> element:

<form action="/submit" method="POST">
  <label for="name">Name:</label>
  <input type="text" id="name" name="name" />

  <button type="submit">Submit</button>
</form>

Key attributes:

  • action — URL where form data is sent
  • method — HTTP method (GET or POST)

Labels

Always pair inputs with labels for accessibility:

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

Why labels matter:

  • Clicking the label focuses the input
  • Screen readers announce the label
  • Improves touch targets on mobile

Input Types

HTML5 provides many specialized input types:

<!-- Text -->
<input type="text" name="username" />

<!-- Email (validates format) -->
<input type="email" name="email" />

<!-- Password (hides input) -->
<input type="password" name="password" />

<!-- Number -->
<input type="number" name="age" min="0" max="120" />

<!-- Phone -->
<input type="tel" name="phone" />

<!-- URL -->
<input type="url" name="website" />

<!-- Date -->
<input type="date" name="birthday" />

<!-- Time -->
<input type="time" name="appointment" />

<!-- Color -->
<input type="color" name="favorite-color" />

<!-- File -->
<input type="file" name="avatar" accept="image/*" />

<!-- Range (slider) -->
<input type="range" name="volume" min="0" max="100" />

<!-- Search -->
<input type="search" name="query" />

Textarea

For multi-line text input:

<label for="message">Message</label>
<textarea id="message" name="message" rows="5" cols="40">
  Default text here...
</textarea>

Select Dropdown

For choosing from a list of options:

<label for="country">Country</label>
<select id="country" name="country">
  <option value="">Select a country</option>
  <option value="eg">Egypt</option>
  <option value="sa">Saudi Arabia</option>
  <option value="ae">UAE</option>
</select>

Checkboxes and Radio Buttons

<!-- Checkbox (multiple selections) -->
<fieldset>
  <legend>Interests</legend>
  <label>
    <input type="checkbox" name="interests" value="html" /> HTML
  </label>
  <label>
    <input type="checkbox" name="interests" value="css" /> CSS
  </label>
  <label>
    <input type="checkbox" name="interests" value="js" /> JavaScript
  </label>
</fieldset>

<!-- Radio button (single selection) -->
<fieldset>
  <legend>Experience Level</legend>
  <label>
    <input type="radio" name="level" value="beginner" /> Beginner
  </label>
  <label>
    <input type="radio" name="level" value="intermediate" /> Intermediate
  </label>
  <label>
    <input type="radio" name="level" value="advanced" /> Advanced
  </label>
</fieldset>

Validation Attributes

HTML5 provides built-in validation:

<!-- Required field -->
<input type="text" name="name" required />

<!-- Minimum/maximum length -->
<input type="text" name="username" minlength="3" maxlength="20" />

<!-- Pattern matching (regex) -->
<input type="tel" name="phone" pattern="[0-9]{10}" />

<!-- Min/max for numbers -->
<input type="number" name="age" min="18" max="120" />

<!-- Email validation -->
<input type="email" name="email" required />

<!-- URL validation -->
<input type="url" name="website" />

Validation Messages

Custom validation messages with JavaScript:

<form id="myForm">
  <label for="email">Email</label>
  <input type="email" id="email" name="email" required />
  <span class="error" aria-live="polite"></span>

  <button type="submit">Submit</button>
</form>

<script>
  const form = document.getElementById('myForm');
  const email = document.getElementById('email');
  const error = document.querySelector('.error');

  email.addEventListener('input', () => {
    if (email.validity.valid) {
      error.textContent = '';
    } else {
      error.textContent = getErrorMessage(email);
    }
  });

  function getErrorMessage(input) {
    if (input.validity.valueMissing) return 'Email is required';
    if (input.validity.typeMismatch) return 'Please enter a valid email';
    return '';
  }
</script>

Fieldset and Legend

Group related form elements:

<form>
  <fieldset>
    <legend>Personal Information</legend>

    <label for="name">Name</label>
    <input type="text" id="name" name="name" required />

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

  <fieldset>
    <legend>Preferences</legend>

    <label>
      <input type="checkbox" name="newsletter" /> Subscribe to newsletter
    </label>
  </fieldset>

  <button type="submit">Submit</button>
</form>

Complete Example

Here’s a complete registration form:

<form action="/register" method="POST">
  <h2>Create Account</h2>

  <fieldset>
    <legend>Account Details</legend>

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

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

    <div>
      <label for="password">Password</label>
      <input
        type="password"
        id="password"
        name="password"
        required
        minlength="8"
      />
      <small>At least 8 characters</small>
    </div>
  </fieldset>

  <fieldset>
    <legend>Profile</legend>

    <div>
      <label for="bio">Bio</label>
      <textarea id="bio" name="bio" rows="4" maxlength="500"></textarea>
      <small>Max 500 characters</small>
    </div>

    <div>
      <label for="role">Role</label>
      <select id="role" name="role" required>
        <option value="">Select a role</option>
        <option value="student">Student</option>
        <option value="developer">Developer</option>
        <option value="designer">Designer</option>
      </select>
    </div>
  </fieldset>

  <label>
    <input type="checkbox" name="terms" required />
    I agree to the <a href="/terms">Terms of Service</a>
  </label>

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

Common Mistakes

  1. Missing labels — Inputs without labels hurt accessibility
  2. Using placeholder as label — Placeholder disappears when typing
  3. No validation — Always validate on both client and server
  4. Missing required attribute — Let HTML handle basic validation
  5. Not grouping related fields — Use fieldset for complex forms