DevRoadmap
Home / Articles / HTML
HTML

HTML Forms: A Complete Guide to Building Forms That Work

HTML forms are how users interact with every web application — login, signup, search, checkout. This complete guide covers every aspect of building forms that are accessible, validated, and backend-ready.

Advertisement

HTML Input Types

HTML5 introduced over a dozen input types that browsers handle with built-in UI and validation. Using the right input type is the single most impactful accessibility and UX improvement you can make to a form.

<!-- Text inputs -->
<input type="text" placeholder="Full name">
<input type="email" placeholder="email@example.com">  <!-- validates email format -->
<input type="password">                               <!-- masks input -->
<input type="tel" placeholder="+1 555 0100">          <!-- numeric keyboard on mobile -->
<input type="url" placeholder="https://...">          <!-- validates URL format -->
<input type="number" min="1" max="100" step="1">      <!-- numeric spinbox -->
<input type="range" min="0" max="100">                 <!-- slider -->
<input type="date">                                    <!-- date picker -->
<input type="color">                                   <!-- color picker -->
<input type="file" accept=".pdf,.jpg,.png">            <!-- file upload -->
<input type="checkbox">                                <!-- boolean toggle -->
<input type="radio" name="plan" value="free">         <!-- one-of-many -->
<input type="hidden" name="csrf" value="token123">    <!-- invisible data -->
<textarea rows="4"></textarea>                        <!-- multi-line text -->
<select><option value="us">United States</option></select>

Accessible Form Structure

Every form input must have an associated label. Screen readers, keyboard navigation, and click-target size all depend on properly associated labels. Never skip labels — placeholder text is not a label.

<!-- ✅ Correct: label associated via 'for' and 'id' -->
<div class="form-group">
  <label for="email">Email Address</label>
  <input type="email" id="email" name="email" required autocomplete="email">
</div>

<!-- ✅ Alternative: label wraps input (implicit association) -->
<label>
  Password
  <input type="password" name="password" autocomplete="current-password">
</label>

<!-- ❌ Wrong: no label, only placeholder -->
<input type="email" placeholder="Enter email">

<!-- Fieldset for grouping related inputs -->
<fieldset>
  <legend>Preferred contact method</legend>
  <label><input type="radio" name="contact" value="email"> Email</label>
  <label><input type="radio" name="contact" value="phone"> Phone</label>
</fieldset>

Built-in HTML Validation

<input
  type="email"
  required                    <!-- cannot be empty -->
  minlength="5"               <!-- minimum character count -->
  maxlength="255"             <!-- maximum character count -->
  pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$"  <!-- regex pattern -->
  aria-describedby="email-hint"
>
<p id="email-hint">Enter your work email address</p>

<!-- Custom validation messages with JavaScript -->
<script>
  document.getElementById("email").addEventListener("invalid", (e) => {
    e.target.setCustomValidity("Please enter a valid email address");
  });
</script>

Handling Forms with JavaScript

const form = document.getElementById("signupForm");

form.addEventListener("submit", async (e) => {
  e.preventDefault(); // stop default browser submit
  
  // Read form data
  const formData = new FormData(form);
  const data = Object.fromEntries(formData); // { email: "...", name: "..." }
  
  // Or read individual fields
  const email = form.elements["email"].value;
  
  // Submit to API
  try {
    const response = await fetch("/api/register", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data)
    });
    
    if (!response.ok) throw new Error("Registration failed");
    
    window.location.href = "/dashboard";
  } catch (error) {
    showError(error.message);
  }
});
Accessibility ChecklistEvery form should: use semantic labels, have visible focus styles, show error messages next to the relevant field, be completable with keyboard only, and not rely solely on color to indicate errors. Test with a screen reader at least once — NVDA (Windows) and VoiceOver (Mac) are free.
Advertisement