← Back to Guides

Building Accessible Forms

Forms are the primary vector for user input. If a form is inaccessible, the user is entirely blocked from completing their goal. Placeholder text is not a label.

1. Explicit Labeling

Every input must have an explicit <label> associated with it via the for and id attributes.

<!-- INCORRECT -->
<input type="email" placeholder="Email Address">

<!-- CORRECT -->
<label for="user_email">Email Address</label>
<input type="email" id="user_email" name="email">

2. Error States and Aria-Describedby

When an input fails validation, do not just change the border color to red. Use aria-invalid="true" and link the error message to the input using aria-describedby so screen readers announce the error when the input receives focus.

<label for="password">Password</label>
<input
  type="password"
  id="password"
  aria-invalid="true"
  aria-describedby="password-error"
>
<span id="password-error" class="error-text">
  Password must be at least 8 characters.
</span>

3. Required Fields

Use the native required attribute. If styling visually, indicate requirement with text (e.g., "(Required)") rather than relying solely on a red asterisk, which can be misread or ignored by some assistive technologies if not implemented correctly.