How to make Forms more accessible?
I once shipped a form where every field had a placeholder but no label. Looked clean. Worked fine for sighted users. Then I tested it with VoiceOver and h...
13 Mar 2024

I once shipped a form where every field had a placeholder but no label. Looked clean. Worked fine for sighted users. Then I tested it with VoiceOver and heard nothing but "edit text, blank" repeated six times. The form was unusable for anyone relying on a screen reader.
Forms are the primary interaction point on most web apps. Login, checkout, search, onboarding — all forms. If they're inaccessible, you've locked people out of your core experience.
Associate labels with inputs
Every input needs a <label> with a for attribute matching the input's id. This creates a programmatic link — screen readers announce the label when the input receives focus, and clicking the label focuses the input.
<label for="username">Username:</label>
<input type="text" id="username" name="username">
Placeholders are not labels. They disappear on input, they have poor contrast, and assistive technology handles them inconsistently.
Surface errors clearly
When validation fails, the user needs to know what went wrong and where. Use aria-live="polite" on error containers so screen readers announce them automatically.
<input type="email" id="email" name="email" aria-describedby="email-error">
<div id="email-error" class="error-message" aria-live="polite">Please enter a valid email address.</div>
Bonus: connect the error to the input with aria-describedby so the context travels with the field.
Support keyboard navigation
Not everyone uses a mouse. Tab order should follow the visual layout. Every interactive element must be focusable and operable with keyboard alone.
<input type="checkbox" id="subscribe" name="subscribe">
<label for="subscribe">Subscribe to our newsletter</label>
Avoid manually setting tabindex values beyond 0 and -1. Let the DOM order handle it. Overriding tab order creates confusion.
Use ARIA attributes for extra context
Mark required fields with aria-required="true". Provide instructions with aria-describedby.
<label for="username">Username:</label>
<input type="text" id="username" name="username" aria-required="true" aria-describedby="username-help">
<div id="username-help">Your username must be between 5 and 10 characters long.</div>
Get the field order right
Label before input. Related fields grouped with <fieldset> and <legend>. Logical top-to-bottom, left-to-right flow. The DOM order should match the visual order.
<fieldset>
<legend>Personal Information</legend>
<label for="first-name">First Name:</label>
<input type="text" id="first-name" name="first-name">
<label for="last-name">Last Name:</label>
<input type="text" id="last-name" name="last-name">
</fieldset>
Test with real assistive technology
Automated tools catch structural issues. They don't catch usability problems. Tab through your form with the keyboard. Turn on VoiceOver or NVDA and fill it out blind. You'll find issues no linter ever will.
The investment is small. The impact is enormous. Accessible forms don't just serve users with disabilities — they're better forms for everyone.