Blog

Form Accessibility Checklist: WCAG 2.1 Requirements for Input Fields

TestParty
TestParty
March 26, 2025

Forms are critical interaction points—account creation, checkout, contact, search, filtering. When forms are inaccessible, users cannot complete tasks that websites exist to enable. For e-commerce, inaccessible checkout forms mean lost sales and excluded customers.

Form accessibility failures appear consistently among the most common WCAG violations. WebAIM's 2024 analysis found missing form labels on 45.9% of homepages. These failures are both frequent and fixable.

This guide provides a comprehensive form accessibility checklist covering labels, instructions, validation, error handling, and keyboard interaction.


WCAG Requirements for Forms

Multiple WCAG success criteria address form accessibility.

Input Purpose (1.3.5 - Level AA)

Form fields collecting common personal information should identify their purpose programmatically, enabling autofill.

Labels or Instructions (3.3.2 - Level A)

Labels or instructions are provided when content requires user input.

Error Identification (3.3.1 - Level A)

If an input error is automatically detected, the item in error is identified and the error described in text.

Error Suggestion (3.3.3 - Level AA)

If an error is detected and suggestions for correction are known, suggestions are provided unless it would jeopardize security.

Error Prevention (3.3.4 - Level AA)

For legal, financial, or data submissions: submissions are reversible, checked, or confirmed.

Consistent Identification (3.2.4 - Level AA)

Components with same functionality are identified consistently across the site.

On Input (3.2.2 - Level A)

Changing a form setting does not automatically cause a change of context unless the user has been advised beforehand.

Name, Role, Value (4.1.2 - Level A)

For all user interface components, the name and role can be programmatically determined; states, properties, and values can be programmatically set.


Form Labels Checklist

Labels are the foundation of accessible forms.

Every Input Needs a Label

Each form field must have a text label that identifies its purpose.

<!-- Correct: Label associated with input -->
<label for="email">Email address</label>
<input type="email" id="email" name="email">

<!-- Correct: Label wrapping input -->
<label>
  Email address
  <input type="email" name="email">
</label>

Checklist:

  • [ ] Every visible form field has a text label
  • [ ] Labels are visible (not just placeholder text)
  • [ ] Labels remain visible while typing
  • [ ] Labels clearly describe expected input

Labels Must Be Programmatically Associated

Visual proximity alone is insufficient. Labels must be programmatically connected to their inputs.

<!-- Associated via for/id -->
<label for="phone">Phone number</label>
<input type="tel" id="phone">

<!-- Associated via nesting -->
<label>
  Phone number
  <input type="tel">
</label>

<!-- Associated via aria-labelledby -->
<span id="phone-label">Phone number</span>
<input type="tel" aria-labelledby="phone-label">

Checklist:

  • [ ] Labels use for attribute matching input id
  • [ ] Or labels wrap their input elements
  • [ ] Or inputs use aria-labelledby referencing label text
  • [ ] Association can be verified programmatically (DevTools, screen reader)

Label Positioning

Label position affects usability and accessibility.

Recommended positions:

  • Text inputs, textareas, selects: Label above or to the left
  • Checkboxes, radio buttons: Label to the right
  • Required field indicators: Consistent position throughout form
<!-- Text field with label above -->
<div class="form-field">
  <label for="name">Full name</label>
  <input type="text" id="name">
</div>

<!-- Checkbox with label after -->
<div class="form-field">
  <input type="checkbox" id="terms">
  <label for="terms">I agree to the terms and conditions</label>
</div>

Checklist:

  • [ ] Label position is consistent throughout form
  • [ ] Labels are visually near their inputs
  • [ ] Position follows user expectations for input type

Placeholder Text Is Not a Label

Placeholder text disappears when users type, leaving them without context. It also typically fails contrast requirements.

<!-- Wrong: Placeholder as only "label" -->
<input type="email" placeholder="Email address">

<!-- Correct: Proper label with optional placeholder -->
<label for="email">Email address</label>
<input type="email" id="email" placeholder="you@example.com">

Checklist:

  • [ ] No form uses placeholder as the only label
  • [ ] Placeholders provide examples, not instructions
  • [ ] Placeholder contrast meets requirements (if used)
  • [ ] Essential information is in labels, not placeholders

Visually Hidden Labels

When visual design requires hiding labels, use accessible hiding techniques:

<label for="search" class="visually-hidden">Search products</label>
<input type="search" id="search" placeholder="Search...">
<button type="submit">Search</button>
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

Checklist:

  • [ ] Hidden labels use visually-hidden technique, not display: none
  • [ ] Screen readers can access hidden labels
  • [ ] Visual design provides sufficient context for sighted users

Form Instructions Checklist

Clear instructions prevent errors and confusion.

General Form Instructions

Provide instructions before the form begins:

<form>
  <p class="form-instructions">
    Fields marked with <span aria-hidden="true">*</span>
    <span class="visually-hidden">asterisk</span> are required.
  </p>

  <label for="name">Name <span aria-hidden="true">*</span></label>
  <input type="text" id="name" required aria-required="true">
</form>

Checklist:

  • [ ] Required field convention is explained before form
  • [ ] Format requirements are stated before input
  • [ ] Instructions are associated with fields programmatically
  • [ ] Instructions are visible before fields receive focus

Field-Specific Instructions

Provide instructions for fields with specific requirements:

<label for="password">Password</label>
<input type="password" id="password" aria-describedby="password-help">
<p id="password-help">Must be at least 8 characters with one number</p>

<label for="phone">Phone number</label>
<input type="tel" id="phone" aria-describedby="phone-format">
<p id="phone-format">Format: (555) 555-5555</p>

Checklist:

  • [ ] Format requirements are provided for formatted inputs
  • [ ] Character/length limits are communicated
  • [ ] Instructions use aria-describedby for association
  • [ ] Instructions are visible before user attempts input

Required Field Identification

Required fields must be clearly identified:

<!-- Visual indicator + programmatic required -->
<label for="email">
  Email address
  <span class="required-indicator" aria-hidden="true">*</span>
  <span class="visually-hidden">(required)</span>
</label>
<input type="email" id="email" required aria-required="true">

Checklist:

  • [ ] Required fields are visually indicated
  • [ ] Visual indicator meaning is explained
  • [ ] Required state is programmatically indicated (required or aria-required)
  • [ ] Optional fields are clear when most fields are required

Error Handling Checklist

Error handling determines whether users can recover from mistakes.

Error Identification

Errors must be clearly communicated:

<!-- Field with error -->
<label for="email">Email address</label>
<input type="email" id="email"
       aria-invalid="true"
       aria-describedby="email-error">
<p id="email-error" class="error-message" role="alert">
  Please enter a valid email address
</p>

Checklist:

  • [ ] Errors are identified in text, not just color
  • [ ] Error messages describe what's wrong
  • [ ] aria-invalid="true" marks fields with errors
  • [ ] Error messages are associated via aria-describedby
  • [ ] Errors are announced to screen readers (via role="alert" or live region)

Error Suggestions

Provide actionable correction guidance:

<!-- Clear suggestion for correction -->
<p id="date-error" class="error-message">
  Invalid date format. Please use MM/DD/YYYY (e.g., 12/31/2024)
</p>

<!-- Don't just repeat the requirement -->
<p id="date-error" class="error-message">
  <!-- Avoid: "Date must be in correct format" - not helpful -->
</p>

Checklist:

  • [ ] Error messages explain how to fix the problem
  • [ ] Examples of valid input are provided
  • [ ] Messages are specific to the error type
  • [ ] Messages avoid technical jargon

Error Summary

For forms with multiple errors, provide a summary:

<div role="alert" aria-labelledby="error-summary-title">
  <h2 id="error-summary-title">Please correct the following errors:</h2>
  <ul>
    <li><a href="#email">Email address is required</a></li>
    <li><a href="#phone">Phone number format is invalid</a></li>
  </ul>
</div>

Checklist:

  • [ ] Error summary appears for multiple errors
  • [ ] Summary appears at top of form or clearly visible location
  • [ ] Summary links to individual error fields
  • [ ] Focus moves to error summary on form submission failure

Focus Management After Errors

Focus should guide users to errors:

<script>
// On form submission failure
function handleFormError() {
  // Move focus to error summary or first error field
  document.getElementById('error-summary').focus();
  // Or first field with error
  document.querySelector('[aria-invalid="true"]').focus();
}
</script>

Checklist:

  • [ ] Focus moves to error summary when form fails validation
  • [ ] Or focus moves to first field with error
  • [ ] Users don't need to search for what went wrong
  • [ ] Screen readers announce errors after focus moves

Inline Validation

Real-time validation should be helpful, not intrusive:

<!-- Validate on blur, not on every keystroke -->
<input type="email" id="email"
       onblur="validateEmail(this)">

Checklist:

  • [ ] Validation occurs on blur, not during typing
  • [ ] Users can complete input before seeing errors
  • [ ] Success states don't distract from task
  • [ ] Validation doesn't trap focus

Keyboard Accessibility Checklist

Forms must be fully operable via keyboard.

Focus Navigation

<!-- Natural focus order via DOM order -->
<form>
  <label for="first">First name</label>
  <input type="text" id="first">

  <label for="last">Last name</label>
  <input type="text" id="last">

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

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

Checklist:

  • [ ] Tab order follows logical flow (typically top-to-bottom, left-to-right)
  • [ ] All form controls are focusable via Tab key
  • [ ] Focus order matches visual order
  • [ ] No positive tabindex values creating unpredictable order

Focus Indicators

/* Ensure visible focus on all form elements */
input:focus,
select:focus,
textarea:focus,
button:focus {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

Checklist:

  • [ ] Focus indicators are visible on all form elements
  • [ ] Focus indicators have sufficient contrast (3:1 minimum)
  • [ ] Custom focus styles are provided if defaults are removed
  • [ ] Focus is visible against all background colors

Form Submission

Checklist:

  • [ ] Forms can be submitted via Enter key
  • [ ] Submit button is keyboard accessible
  • [ ] Submission feedback is announced to screen readers
  • [ ] Focus is managed appropriately after submission

Custom Controls

Custom form controls (custom selects, date pickers) need keyboard support:

Checklist:

  • [ ] Custom controls are focusable
  • [ ] Expected keyboard patterns work (arrows, Enter, Space, Escape)
  • [ ] Custom controls have appropriate ARIA roles and states
  • [ ] Focus is visible on custom controls

Input Types and Autocomplete

Using appropriate input types and autocomplete improves accessibility and usability.

Semantic Input Types

<!-- Use appropriate input types -->
<input type="email" id="email">      <!-- Email keyboard on mobile -->
<input type="tel" id="phone">        <!-- Phone keyboard on mobile -->
<input type="url" id="website">      <!-- URL keyboard on mobile -->
<input type="number" id="quantity">  <!-- Number keyboard -->
<input type="date" id="birthday">    <!-- Native date picker -->
<input type="search" id="search">    <!-- Search semantics -->

Checklist:

  • [ ] Email fields use type="email"
  • [ ] Phone fields use type="tel"
  • [ ] URL fields use type="url"
  • [ ] Numeric fields use type="number" where appropriate
  • [ ] Date fields use type="date" or accessible date picker
  • [ ] Search fields use type="search"

Autocomplete Attributes

Enable browser autofill with autocomplete attributes:

<input type="text" id="name" autocomplete="name">
<input type="email" id="email" autocomplete="email">
<input type="tel" id="phone" autocomplete="tel">
<input type="text" id="street" autocomplete="street-address">
<input type="text" id="city" autocomplete="address-level2">
<input type="text" id="state" autocomplete="address-level1">
<input type="text" id="zip" autocomplete="postal-code">
<input type="text" id="country" autocomplete="country-name">
<input type="text" id="cc-number" autocomplete="cc-number">

Checklist:

  • [ ] Personal information fields have autocomplete attributes
  • [ ] autocomplete values match expected input
  • [ ] Address fields use appropriate address tokens
  • [ ] Payment fields use cc-* tokens
  • [ ] Fields don't have autocomplete="off" without security justification

Grouping Related Controls

Related form controls should be grouped logically.

Fieldset and Legend

Group related fields with <fieldset> and <legend>:

<!-- Address group -->
<fieldset>
  <legend>Shipping Address</legend>
  <label for="street">Street address</label>
  <input type="text" id="street">

  <label for="city">City</label>
  <input type="text" id="city">

  <label for="zip">ZIP code</label>
  <input type="text" id="zip">
</fieldset>

<!-- Radio group -->
<fieldset>
  <legend>Shipping speed</legend>
  <input type="radio" id="standard" name="shipping" value="standard">
  <label for="standard">Standard (5-7 days)</label>

  <input type="radio" id="express" name="shipping" value="express">
  <label for="express">Express (2-3 days)</label>
</fieldset>

Checklist:

  • [ ] Radio button groups are in fieldsets with legends
  • [ ] Checkbox groups with shared purpose are in fieldsets
  • [ ] Related fields (address, payment) are grouped
  • [ ] Legends describe the group purpose
  • [ ] Nested fieldsets are avoided (can cause screen reader issues)

ARIA Grouping

For non-fieldset grouping needs:

<div role="group" aria-labelledby="password-group-label">
  <h3 id="password-group-label">Create Password</h3>
  <label for="password">Password</label>
  <input type="password" id="password">

  <label for="confirm">Confirm password</label>
  <input type="password" id="confirm">
</div>

Multi-Step Forms

Multi-step forms require additional accessibility considerations.

Progress Indication

<nav aria-label="Checkout progress">
  <ol>
    <li aria-current="step">
      <span class="step-number">1</span>
      Shipping
    </li>
    <li>
      <span class="step-number">2</span>
      Payment
    </li>
    <li>
      <span class="step-number">3</span>
      Review
    </li>
  </ol>
</nav>

Checklist:

  • [ ] Progress indicator shows current step
  • [ ] Total number of steps is clear
  • [ ] Completed steps are distinguishable
  • [ ] Current step is programmatically indicated (aria-current="step")

Step Navigation

Checklist:

  • [ ] Users can move between steps
  • [ ] Back navigation preserves entered data
  • [ ] Validation occurs before step progression
  • [ ] Focus moves to new step content

Data Persistence

Checklist:

  • [ ] Data persists when navigating between steps
  • [ ] Session timeout warnings are provided
  • [ ] Users can save progress where appropriate
  • [ ] Lost data scenarios are minimized

Common Form Accessibility Failures

Avoid these frequently encountered issues.

Icon-Only Buttons Without Labels

<!-- Inaccessible -->
<button type="submit">
  <i class="icon-search"></i>
</button>

<!-- Accessible -->
<button type="submit" aria-label="Search">
  <i class="icon-search" aria-hidden="true"></i>
</button>

<!-- Better: visible text -->
<button type="submit">
  <i class="icon-search" aria-hidden="true"></i>
  Search
</button>

Custom Selects Without Keyboard Support

Custom-styled selects often break keyboard accessibility:

<!-- Use native select when possible -->
<label for="country">Country</label>
<select id="country">
  <option value="us">United States</option>
  <option value="ca">Canada</option>
</select>

<!-- If custom: ensure full keyboard support -->
<div role="listbox" aria-labelledby="country-label" tabindex="0">
  <!-- Must support arrow keys, Enter, Escape, type-ahead -->
</div>

Date Pickers Requiring Mouse

Many date picker widgets fail keyboard accessibility:

Checklist for date pickers:

  • [ ] Can open via keyboard
  • [ ] Can navigate dates via arrow keys
  • [ ] Can select via Enter
  • [ ] Can close via Escape
  • [ ] Current selection is announced
  • [ ] Alternative text input is available

Color-Only Error Indication

<!-- Wrong: Red border only -->
<input type="email" class="error-border">

<!-- Correct: Text message + icon + styling -->
<input type="email"
       aria-invalid="true"
       aria-describedby="email-error">
<p id="email-error">
  <span class="error-icon" aria-hidden="true">!</span>
  Please enter a valid email address
</p>

Testing Form Accessibility

Verify form accessibility through systematic testing.

Automated Testing

Automated tools catch:

  • Missing labels
  • Missing label associations
  • Missing required indicators
  • Missing autocomplete attributes
  • Basic ARIA issues

Manual Testing

Keyboard testing:

  1. Tab through entire form
  2. Verify all fields are reachable
  3. Test custom controls with arrows, Enter, Escape
  4. Verify form submission via Enter
  5. Check focus management after errors

Screen reader testing:

  1. Navigate to each field
  2. Verify labels are announced
  3. Check instructions are announced
  4. Test error handling
  5. Verify grouping is communicated

See our Screen Reader Testing Guide and Keyboard Navigation Testing guides.


Taking Action

Form accessibility determines whether users can complete essential tasks. The checklist above covers the major areas: labels, instructions, error handling, keyboard accessibility, and proper grouping.

Start with your highest-traffic forms—checkout, login, contact—and systematically verify each checklist item. Fix issues by priority: missing labels first, then error handling, then enhanced usability.

Schedule a TestParty demo and get a 14-day compliance implementation plan.


Related Resources

Contact Us

Automate the software work for accessibility compliance, end-to-end.

Empowering businesses with seamless digital accessibility solutions—simple, inclusive, effective.

Book a Demo