FormsARIAWCAGAccessibility

How to Make Your Forms Accessible: Complete Guide

ClearA11y Team7 min read

Why Form Accessibility Matters

Forms are how users interact with your website - signing up, checking out, contacting you, searching. If your forms aren't accessible, you're locking out users who:

  • Use screen readers
  • Navigate with keyboards only
  • Have motor impairments
  • Use voice control software
  • Inaccessible forms are also one of the most common reasons for ADA lawsuits. The good news? Most form accessibility issues are easy to fix.

    The Fundamentals

    Every Input Needs a Label

    This is the most common form accessibility failure. Every input must have a programmatically associated label.

    <!-- Bad: No label association -->
    <span>Email</span>
    <input type="email">
    
    <!-- Bad: Placeholder is not a label -->
    <input type="email" placeholder="Email">
    
    <!-- Good: Label with for/id association -->
    <label for="email">Email</label>
    <input type="email" id="email">
    
    <!-- Also good: Wrapping label -->
    <label>
      Email
      <input type="email">
    </label>

    Screen readers announce the label when users focus on the input. Without it, users have no idea what information to enter.

    Use Proper Input Types

    HTML5 input types provide built-in accessibility benefits:

    <input type="email">    <!-- Email keyboard on mobile, validation -->
    <input type="tel">      <!-- Phone keyboard on mobile -->
    <input type="url">      <!-- URL keyboard, validation -->
    <input type="number">   <!-- Number keyboard, increment controls -->
    <input type="date">     <!-- Native date picker -->
    <input type="search">   <!-- Search semantics, clear button -->

    Add Autocomplete Attributes

    Help users fill forms faster and reduce errors:

    <input type="text" autocomplete="name">
    <input type="email" autocomplete="email">
    <input type="tel" autocomplete="tel">
    <input type="text" autocomplete="street-address">
    <input type="text" autocomplete="postal-code">
    <input type="text" autocomplete="cc-number">

    This is also a WCAG 2.1 Level AA requirement (Success Criterion 1.3.5).

    Required Fields

    Mark Required Fields Clearly

    Don't rely on color alone to indicate required fields:

    <!-- Good: Visual indicator + aria-required -->
    <label for="name">
      Name <span aria-hidden="true">*</span>
      <span class="sr-only">(required)</span>
    </label>
    <input type="text" id="name" aria-required="true" required>
    
    <!-- Include instructions -->
    <p class="form-instructions">Fields marked with * are required</p>

    Use the required Attribute

    The HTML required attribute provides native validation:

    <input type="email" id="email" required>

    Error Handling

    Poor error handling is frustrating for everyone and impossible for screen reader users. Here's how to do it right:

    Identify Errors Clearly

    <!-- Associate error with input using aria-describedby -->
    <label for="email">Email</label>
    <input
      type="email"
      id="email"
      aria-invalid="true"
      aria-describedby="email-error"
    >
    <span id="email-error" class="error">
      Please enter a valid email address
    </span>

    Announce Errors to Screen Readers

    Use aria-live regions to announce errors as they appear:

    <div aria-live="polite" class="error-summary">
      <!-- Errors inserted here will be announced -->
    </div>

    Provide an Error Summary

    For long forms, provide a summary at the top:

    <div role="alert" class="error-summary">
      <h2>There were 2 errors with your submission</h2>
      <ul>
        <li><a href="#email">Email: Please enter a valid email</a></li>
        <li><a href="#password">Password: Must be at least 8 characters</a></li>
      </ul>
    </div>

    Be Specific About What's Wrong

    <!-- Bad: Vague error -->
    <span class="error">Invalid input</span>
    
    <!-- Good: Specific and helpful -->
    <span class="error">Password must be at least 8 characters and include a number</span>

    Form Layout and Grouping

    Group Related Fields

    Use fieldset and legend for related inputs:

    <fieldset>
      <legend>Shipping Address</legend>
    
      <label for="street">Street Address</label>
      <input type="text" id="street" autocomplete="street-address">
    
      <label for="city">City</label>
      <input type="text" id="city" autocomplete="address-level2">
    
      <label for="zip">ZIP Code</label>
      <input type="text" id="zip" autocomplete="postal-code">
    </fieldset>

    Radio Buttons and Checkboxes

    Always group these with fieldset:

    <fieldset>
      <legend>Preferred contact method</legend>
    
      <input type="radio" id="contact-email" name="contact" value="email">
      <label for="contact-email">Email</label>
    
      <input type="radio" id="contact-phone" name="contact" value="phone">
      <label for="contact-phone">Phone</label>
    
      <input type="radio" id="contact-mail" name="contact" value="mail">
      <label for="contact-mail">Mail</label>
    </fieldset>

    Accessible Form Patterns

    Search Forms

    <form role="search">
      <label for="search" class="sr-only">Search</label>
      <input type="search" id="search" placeholder="Search...">
      <button type="submit">
        <span class="sr-only">Submit search</span>
        <svg aria-hidden="true"><!-- search icon --></svg>
      </button>
    </form>

    Login Forms

    <form>
      <h1>Sign In</h1>
    
      <label for="username">Email or Username</label>
      <input type="text" id="username" autocomplete="username" required>
    
      <label for="password">Password</label>
      <input type="password" id="password" autocomplete="current-password" required>
    
      <button type="submit">Sign In</button>
    
      <a href="/forgot-password">Forgot password?</a>
    </form>

    Multi-Step Forms

    <!-- Indicate progress -->
    <nav aria-label="Form progress">
      <ol>
        <li aria-current="step">1. Personal Info</li>
        <li>2. Shipping</li>
        <li>3. Payment</li>
      </ol>
    </nav>
    
    <!-- Each step should have a heading -->
    <h2>Step 1: Personal Information</h2>

    Testing Your Forms

    Keyboard Testing

    1. Tab through every field - is the order logical?

    2. Can you select options in dropdowns with arrow keys?

    3. Can you submit the form with Enter?

    4. Can you cancel/close modals with Escape?

    Screen Reader Testing

    1. Are all labels announced?

    2. Are required fields identified?

    3. Are errors announced when they appear?

    4. Is the error summary read when the form is submitted?

    Automated Testing

    Use ClearA11y to scan your forms for:

  • Missing labels
  • Empty buttons
  • Missing form field names
  • ARIA misuse
  • Quick Reference Checklist

  • Every input has a visible, associated label
  • Required fields are marked (not just with color)
  • Input types match the expected data
  • Autocomplete attributes are set
  • Errors are specific and associated with fields
  • Error summary links to problem fields
  • Related fields are grouped with fieldset/legend
  • Form can be completed with keyboard only
  • Focus order is logical
  • Submit button has clear text
  • Scan Your Forms Now

    Don't guess whether your forms are accessible. Run a free scan with ClearA11y and get a complete report with AI-powered fix suggestions you can copy and paste directly into your code.

    Check Your Site's Accessibility

    Find and fix accessibility issues with AI-powered code suggestions.

    Start Free Scan

    Stay Updated on Web Accessibility

    Get practical accessibility tips, WCAG updates, and guides delivered to your inbox. No spam, unsubscribe anytime.

    We respect your privacy. Unsubscribe at any time.