Intermediate 25 min read Code examples

Accessible Forms Design

Forms are where users complete the most critical tasks on your site — and where accessibility failures are most disabling. Here is how to get it right.

Label Association

Every form input must have a programmatically associated label (WCAG 2.2 SC 1.3.1, 3.3.2). This enables screen readers to announce the field's purpose when focused, and makes the click target larger by allowing users to click the label to focus the field.

Method 1: for/id association (preferred)

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

Method 2: wrapping label

<label>
  Email address
  <input type="email" name="email" autocomplete="email"/>
</label>

Method 3: aria-label (when no visible label)

<!-- Use sparingly — visible labels are always preferred -->
<input
  type="search"
  aria-label="Search the site"
  placeholder="Search..."
/>

Never rely on placeholder text as a label. Placeholders disappear when typing begins, have insufficient contrast in most browsers, and are not reliably announced by all screen readers.

Required Fields

Required fields must be identified both visually and programmatically. If you use an asterisk (*), explain its meaning at the start of the form.

<!-- Explain the asterisk -->
<p>Fields marked with <span aria-hidden="true">*</span> are required.</p>

<label for="name">
  Full name
  <span aria-hidden="true">*</span>
  <span class="sr-only">(required)</span>
</label>
<input
  type="text"
  id="name"
  required
  aria-required="true"
/>

Input Types

Use the correct type attribute on inputs. This provides the right virtual keyboard on mobile, enables browser autofill, and communicates the expected format to assistive technology.

Type Use For Mobile Keyboard
type="email"Email addressesShows @ and . keys
type="tel"Phone numbersNumeric pad
type="number"Numeric values (quantities)Numeric pad
type="url"Web addressesShows .com and / keys
type="search"Search inputsShows Search button
type="date"Calendar date selectionDate picker widget
type="password"Password inputsMasked keyboard
type="checkbox"Multiple selection
type="radio"Single selection from a group

Error Handling & Validation

Form errors are one of the most challenging areas for accessible design. WCAG 2.2 SC 3.3.1 (Error Identification) and 3.3.3 (Error Suggestion) require errors to be clearly identified with text descriptions and suggestions for fixing them.

Accessible error pattern

<div class="field-group">
  <label for="email">Email address</label>
  <input
    type="email"
    id="email"
    aria-invalid="true"
    aria-describedby="email-error"
  />
  <p id="email-error" role="alert">
    <i class="fas fa-xmark-circle" aria-hidden="true"></i>
    Please enter a valid email address (example: [email protected]).
  </p>
</div>

Move focus to error summary after failed submission. A summary listing all errors at the top of the form (or the first error) helps screen reader users quickly understand what needs fixing.

Validate on submission, not on every keystroke. Immediate error feedback while typing is disruptive for screen reader users. Validate on blur (when the user leaves a field) or on form submission.

Never rely on color alone to indicate an error. Red border + error icon + error message text = accessible. Red border alone = fail.

Fieldsets & Legends

When a group of related controls share a common purpose (radio buttons, checkboxes), wrap them in a <fieldset> with a <legend> describing the group. Screen readers prepend the legend to each control's label.

<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>
  <label><input type="radio" name="contact" value="text"/> Text message</label>
</fieldset>

When a screen reader focuses on the "Email" radio button above, it announces: "Preferred contact method. Email. Radio button." The legend provides essential context.

Placeholder vs Label

Placeholder

  • Disappears when user types
  • Often fails 4.5:1 contrast ratio
  • Not consistently announced by screen readers
  • Cannot serve as a label alone
  • Good use: hint text ("e.g., [email protected]")

Label

  • Always visible — even after typing
  • Increases click target size
  • Reliably announced by all screen readers
  • Required for all form inputs
  • Can be paired with placeholder hint text

Keyboard Navigation

All form interactions must be fully keyboard-accessible (WCAG 2.2 SC 2.1.1). Key behaviors to verify:

Key Expected Behavior
TabMove focus to next focusable element
Shift+TabMove focus to previous focusable element
SpaceToggle checkboxes; activate buttons
EnterSubmit form; follow links; activate buttons
↑ ↓Move between radio button options in a group
EscClose dropdowns, date pickers, and custom select widgets

Ensure focus order follows a logical, meaningful sequence (top-to-bottom, left-to-right). Multi-column form layouts can break logical tab order if not carefully structured.

ARIA for Forms

When native HTML semantics are insufficient, ARIA attributes can enhance form accessibility:

aria-required="true"

Use in addition to the required attribute. Some older assistive technologies only respond to one or the other.

aria-invalid="true"

Set after failed validation. Causes screen readers to announce "invalid" when the field is focused.

aria-describedby

Associate helper text (hints, character counts, format requirements) with an input field programmatically.

aria-errormessage

Newer attribute that explicitly points to an error message element. Use alongside aria-invalid. Has less support than aria-describedby currently.

aria-live="polite"

On a container that will receive dynamic validation messages. Causes the message to be read when the user pauses.

aria-expanded

On custom select/combobox inputs to communicate whether the dropdown is open or closed.

Complete Accessible Form Example

Here is a complete, accessible contact form example incorporating all the principles above:

<form novalidate aria-label="Contact us">

  <!-- Error summary (shown after failed submission) -->
  <div role="alert" id="form-errors" aria-live="assertive"></div>

  <p>Fields marked <span aria-hidden="true">*</span><span class="sr-only">with an asterisk</span> are required.</p>

  <div class="field-group">
    <label for="fullname">
      Full name <span aria-hidden="true">*</span></label>
    <input
      type="text" id="fullname" name="fullname"
      autocomplete="name"
      required aria-required="true"
    />
  </div>

  <div class="field-group">
    <label for="email">
      Email address <span aria-hidden="true">*</span></label>
    <input
      type="email" id="email" name="email"
      autocomplete="email"
      required aria-required="true"
      aria-describedby="email-hint"
    />
    <p id="email-hint" class="hint-text">Example: [email protected]</p>
  </div>

  <fieldset>
    <legend>Service interest</legend>
    <label><input type="checkbox" name="services" value="audit"/> Accessibility Audit</label>
    <label><input type="checkbox" name="services" value="remediation"/> Remediation</label>
    <label><input type="checkbox" name="services" value="training"/> Training</label>
  </fieldset>

  <button type="submit">Send Message</button>

</form>

Need a Form Accessibility Audit?

Our team will audit every form on your site against WCAG 2.2 AA and provide detailed, actionable remediation guidance.

Get a Forms Audit