HTML
07 / 12

Forms & Input Validation

HTML Forms & Input Validation

HTML5 provides extensive form capabilities including validation, many input types, and the FormData API. Understanding forms is fundamental to web development.

Form Structure

<form action="/submit" method="post" id="signup-form" novalidate>
  <!-- novalidate disables browser's native validation UI — useful when custom validation -->

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

    <!-- Proper label association — click label focuses input -->
    <label for="name">Full Name</label>
    <input type="text" id="name" name="name" required autocomplete="name">

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

  <!-- Submit button inside form is associated automatically -->
  <button type="submit">Create Account</button>

  <!-- Reset clears all fields to their default values -->
  <button type="reset">Clear Form</button>

  <!-- Button outside form can be linked via form attribute -->
</form>
<button form="signup-form" type="submit">Submit from outside</button>

Input Types

<!-- Text inputs -->
<input type="text" placeholder="Enter text">
<input type="email" autocomplete="email">
<input type="password" autocomplete="current-password" minlength="8">
<input type="tel" autocomplete="tel" pattern="[0-9]{10}">
<input type="url">
<input type="search">    <!-- shows clear button on some browsers -->

<!-- Numbers -->
<input type="number" min="0" max="100" step="5">
<input type="range" min="0" max="10" value="5">   <!-- slider -->

<!-- Dates & Times -->
<input type="date" min="2024-01-01" max="2024-12-31">
<input type="time" step="900">  <!-- step in seconds: 900 = 15min increments -->
<input type="datetime-local">
<input type="month">
<input type="week">

<!-- Pickers -->
<input type="color" value="#0070f3">
<input type="file" accept="image/*,.pdf" multiple>

<!-- Selection -->
<input type="checkbox" id="agree" name="agree" value="yes" checked>
<input type="radio" name="size" value="sm"> Small
<input type="radio" name="size" value="lg"> Large

<!-- Hidden -->
<input type="hidden" name="csrf_token" value="abc123">
<input type="hidden" name="user_id" value="42">

Validation Attributes

<!-- Built-in validation (works without JavaScript) -->
<input type="email" required>
  <!-- required: must not be empty -->
  <!-- type="email": must match email format -->

<input type="text" minlength="2" maxlength="100" required>
  <!-- minlength/maxlength: character count constraints -->

<input type="number" min="1" max="99" step="1">
  <!-- min/max: value range; step: increments -->

<input type="text" pattern="[A-Za-z]{3,}" title="At least 3 letters only">
  <!-- pattern: regex validation; title: shown in error tooltip -->

<input type="url" required>

<!-- Textarea -->
<textarea maxlength="500" required></textarea>

<!-- Custom validation with JavaScript -->
<input type="text" id="username">
<script>
  document.getElementById('username').addEventListener('input', (e) => {
    const el = e.target;
    if (!/^[a-z0-9_]+$/.test(el.value)) {
      el.setCustomValidity('Only lowercase letters, numbers, and underscores');
    } else {
      el.setCustomValidity('');  // clear error
    }
  });
</script>

Select, Datalist & Textarea

<!-- Select dropdown -->
<select name="country" required>
  <option value="" disabled selected>Choose a country</option>
  <optgroup label="Europe">
    <option value="uk">United Kingdom</option>
    <option value="de">Germany</option>
  </optgroup>
  <optgroup label="Americas">
    <option value="us">United States</option>
  </optgroup>
</select>

<!-- Multiple select -->
<select name="skills" multiple size="4">
  <option value="js">JavaScript</option>
  <option value="ts" selected>TypeScript</option>
  <option value="py">Python</option>
</select>

<!-- Datalist — autocomplete suggestions for text input -->
<input type="text" list="frameworks" name="framework">
<datalist id="frameworks">
  <option value="React">
  <option value="Vue">
  <option value="Angular">
  <option value="Svelte">
</datalist>

<!-- Textarea -->
<textarea name="message" rows="4" cols="50"
  placeholder="Your message..." maxlength="1000"></textarea>

FormData API

// Intercept form submission and send via fetch
document.getElementById('signup-form').addEventListener('submit', async (e) => {
  e.preventDefault();

  const formData = new FormData(e.target);

  // Read values
  const name = formData.get('name');        // single value
  const skills = formData.getAll('skills'); // multiple values (checkboxes)

  // Modify before sending
  formData.set('email', formData.get('email').toLowerCase());
  formData.append('timestamp', Date.now().toString());

  // Send as JSON
  const data = Object.fromEntries(formData.entries());
  const res = await fetch('/api/signup', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });

  // Send as multipart/form-data (for file uploads)
  const res2 = await fetch('/api/upload', {
    method: 'POST',
    body: formData,  // don't set Content-Type — browser sets boundary automatically
  });
});

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free