Forms are critical to web interactions—signing up, logging in, making purchases, submitting applications. Yet forms are where accessibility most commonly fails. A form that's frustrating for some users may be completely unusable for others.
Every Input Needs a Label
This is the most important rule. Every form input must have an associated label that screen readers can announce.
Method 1: Using the for/id Connection
<label for="email">Email Address</label>
<input type="email" id="email" name="email">
Method 2: Wrapping the Input
<label>
Email Address
<input type="email" name="email">
</label>
What About Placeholders?
Placeholders are NOT labels. They disappear when users start typing, leaving no visible label. Always use a proper label element.
Required Fields
Mark required fields clearly for all users.
<label for="email">
Email Address <span aria-hidden="true">*</span>
<span class="visually-hidden">(required)</span>
</label>
<input type="email" id="email" required aria-required="true">
Grouping Related Fields
Use fieldset and legend for related fields like radio buttons or checkbox groups.
<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>
Error Messages
When validation fails, users need to know what went wrong and how to fix it.
Connecting Errors to Inputs
<label for="password">Password</label>
<input
type="password"
id="password"
aria-invalid="true"
aria-describedby="password-error"
>
<span id="password-error" role="alert">
Password must be at least 8 characters
</span>
Key attributes:
aria-invalid="true": Indicates the field has an erroraria-describedby: Links the input to its error messagerole="alert": Announces the error immediately to screen readers
Autocomplete Attributes
The autocomplete attribute helps browsers and password managers fill in common fields:
<input type="text" autocomplete="name" name="fullname">
<input type="email" autocomplete="email" name="email">
<input type="tel" autocomplete="tel" name="phone">
<input type="password" autocomplete="new-password" name="password">
Testing Your Forms
- Navigate using only the keyboard (Tab, Shift+Tab, Space, Enter)
- Test with a screen reader (VoiceOver, NVDA, or JAWS)
- Verify all labels are announced
- Check that errors are announced and describe how to fix them
- Run an automated scan with SiteDNA to catch common issues