Accessible Forms: The Complete WCAG 2.2 Guide
Forms are where most users convert — and where accessibility barriers hurt most. This guide walks through labels, required fields, inline validation, accessible errors, grouping, autocomplete, and multi-step patterns, with copy-ready code that works for keyboards and screen readers.
Why Form Accessibility Matters
Forms are the moment a website asks a user to act — sign in, check out, book, apply, contact. When a form is inaccessible, the failure is total: the user cannot complete the task at all. That is why forms dominate real-world accessibility complaints and are among the most frequently cited barriers in ADA web lawsuits. A missing label, an unannounced error, or a keyboard trap in a date picker can quietly turn away a large share of your visitors.
The good news: accessible forms are largely a matter of using the right native HTML and a few ARIA attributes correctly. Nearly everything below is built on four WCAG 2.2 ideas: label every control, communicate state in text, help users recover from mistakes, and never require the mouse.
The WCAG 2.2 Criteria That Govern Forms
| Criterion | Level | What it requires for forms |
|---|---|---|
| 1.3.1 Info & Relationships | A | Labels programmatically associated; groups use fieldset/legend. |
| 1.3.5 Identify Input Purpose | AA | Set autocomplete tokens on fields collecting user data. |
| 1.4.1 Use of Color | A | Errors and required state not shown by color alone. |
| 2.4.6 Headings & Labels | AA | Labels are descriptive and unambiguous. |
| 3.3.1 Error Identification | A | Errors identified in text and the item is described. |
| 3.3.2 Labels or Instructions | A | Provide labels and instructions when input is required. |
| 3.3.3 Error Suggestion | AA | Suggest how to fix an error when the fix is known. |
| 3.3.4 Error Prevention | AA | Legal/financial submissions are reversible, checked, or confirmable. |
| 3.3.7 Redundant Entry | A | Don't make users re-enter info already provided in the process. |
| 3.3.8 Accessible Authentication | AA | No cognitive function test (like a puzzle) required to log in. |
| 4.1.2 Name, Role, Value | A | Custom controls expose a name, role, and current value. |
3.3.7 Redundant Entry, 3.3.8 Accessible Authentication, and the dragging/target-size criteria are new in WCAG 2.2 and matter most for login and checkout forms.
1. Label Every Control
Every input, select, and textarea needs a programmatically associated label. The most robust method is an explicit <label> whose forattribute matches the input's id. This gives the field an accessible name and makes the label a click target that focuses the input.
<!-- Explicit label: preferred -->
<label for="email">Email address</label>
<input type="email" id="email" name="email"
autocomplete="email" required />
<!-- Instruction that isn't the label? Tie it with aria-describedby -->
<label for="pw">Password</label>
<input type="password" id="pw" name="pw"
aria-describedby="pw-hint" autocomplete="current-password" />
<p id="pw-hint">Use at least 12 characters.</p>Avoid using a placeholder as the label — it disappears on input, often fails contrast, and is not reliably announced. When a visible label is genuinely impossible (for example, a search field next to a labeled button), use aria-label or aria-labelledby so the control still has an accessible name under 4.1.2.
2. Required Fields & Instructions
Communicate the required state in more than one way, and put instructions before the input they describe so users encounter them in time (3.3.2).
<label for="name">
Full name <span aria-hidden="true">*</span>
<span class="sr-only">(required)</span>
</label>
<input type="text" id="name" name="name" required
autocomplete="name" />
<!-- Explain the asterisk once, at the top of the form -->
<p>Fields marked * are required.</p>The native requiredattribute makes screen readers announce “required,” and the visible text (or a clearly explained asterisk) covers sighted users who do not use assistive tech. Do not signal required state with color alone — that fails 1.4.1 Use of Color.
3. Accessible Validation & Error Messages
Error handling is where most forms fail their users. A red outline means nothing to a screen reader and nothing to a colorblind user. Make every error do three things: describe the problem in specific text, tie the message to its field, and mark the field invalid.
<label for="email">Email address</label>
<input
type="email"
id="email"
name="email"
autocomplete="email"
aria-describedby="email-error"
aria-invalid="true"
/>
<p id="email-error" class="error">
Enter a valid email address, such as name@example.com.
</p>Because aria-describedby points at the message, a screen reader reads the error whenever the field gains focus. aria-invalid="true" reports the field as invalid. Set aria-invalid to false (or remove it) once the field is corrected.
On submit: focus and summarize
When validation runs on submit, do not leave keyboard and screen reader users hunting for what went wrong. Render an error summary at the top of the form, move focus to it (or to the first invalid field), and let each summary item link to its field.
<div role="alert" tabindex="-1" id="error-summary">
<h2>There are 2 problems with your submission</h2>
<ul>
<li><a href="#email">Enter a valid email address</a></li>
<li><a href="#pw">Password must be at least 12 characters</a></li>
</ul>
</div>The role="alert" live region announces the summary the moment it appears; tabindex="-1" lets you move focus to it programmatically. For validation that happens as the user types, prefer validating on blur rather than on every keystroke, and announce dynamic messages through a polite live region so you do not interrupt typing. This satisfies 3.3.1 and 3.3.3.
4. Group Related Controls
Radio buttons, checkbox sets, and related field clusters need a group label so the shared question survives when a screen reader user navigates option by option. Use <fieldset> and <legend>.
<fieldset>
<legend>Shipping method</legend>
<input type="radio" id="ship-standard" name="ship" value="standard" />
<label for="ship-standard">Standard (5–7 days)</label>
<input type="radio" id="ship-express" name="ship" value="express" />
<label for="ship-express">Express (2 days)</label>
</fieldset>Screen readers announce “Shipping method, Standard, radio button 1 of 2” — the option makes sense in context. For custom radio/checkbox widgets, replicate this with role="radiogroup" and aria-labelledby. See our ARIA roles & attributes reference for the exact patterns.
5. Autocomplete & Input Purpose
WCAG 1.3.5 Identify Input Purpose asks you to declare what a field collects so browsers, password managers, and personalization tools can help. Use the right autocomplete token and the right type/inputmode so mobile keyboards match the data.
<input autocomplete="given-name" name="fname" ... />
<input autocomplete="family-name" name="lname" ... />
<input autocomplete="email" type="email" inputmode="email" ... />
<input autocomplete="tel" type="tel" inputmode="tel" ... />
<input autocomplete="postal-code" name="zip" inputmode="numeric" ... />
<input autocomplete="street-address" name="addr" ... />Correct autocomplete tokens dramatically reduce typing for people with motor and cognitive disabilities and cut form-abandonment for everyone.
Keyboard Support
- Every control reachable and operable with Tab, arrows, Space, and Enter.
- Logical focus order that follows the visual layout.
- A visible focus indicator on every field and button.
- No keyboard traps in custom date pickers or comboboxes.
- Enter submits from a text input as users expect.
Full detail in the keyboard accessibility guide.
Screen Reader Support
- Each field announces its label, type, and required state.
- Errors announced and reachable via
aria-describedby. - Groups announce their
legendor group label. - Dynamic messages exposed through ARIA live regions.
- Submit success and failure both announced.
Test with real AT — see the screen reader testing guide.
6. Multi-Step Forms & Error Prevention
Long forms — checkout, applications, onboarding — benefit from being split into steps, but each step must remain accessible:
- Announce step changes. Move focus to the new step's heading and expose progress (“Step 2 of 4”) in text, not color alone.
- Don't make users re-enter data. Carry values forward; WCAG 2.2's 3.3.7 Redundant Entry requires it.
- Make submissions recoverable. For legal, financial, or data-deleting actions, provide review, confirm, or undo (3.3.4 Error Prevention).
- Keep authentication accessible. Don't force cognitive puzzles to log in; support paste and password managers (3.3.8).
Common Mistakes & How to Fix Them
| Anti-pattern | Why it fails | The fix |
|---|---|---|
| Placeholder text used as the only label. | It vanishes on input and is inconsistently announced. | Add a persistent visible <label> tied to the input with for/id. |
| Errors shown only with a red border or red text. | Color-only cues fail colorblind users and screen readers (WCAG 1.4.1). | Add a text message, aria-describedby, and aria-invalid="true". |
| A <div> or <span> styled to look like a button for submit. | Not focusable or operable by keyboard or assistive tech. | Use a real <button type="submit"> element. |
| Radio buttons or checkboxes with no shared group label. | The question is lost when navigating option by option. | Wrap them in <fieldset> with a descriptive <legend>. |
| Validation that blocks submit with no explanation of what's wrong. | Users cannot recover (WCAG 3.3.1, 3.3.3). | Identify each error in text and suggest a correction. |
| Auto-advancing focus between segmented inputs (e.g. OTP boxes). | It disorients screen reader and switch users and breaks editing. | Use a single labeled input, or make auto-advance optional and reversible. |
How to Test Your Form
- Keyboard pass. Unplug the mouse. Tab through the whole form, operate every control, trigger and dismiss validation, and submit — all without a trap.
- Screen reader pass. With NVDA, VoiceOver, or JAWS, confirm each field announces its label, required state, and any error.
- Automated scan. Run the page through our URL accessibility auditor to catch missing labels and low contrast.
- Zoom & reflow. At 200% zoom and 320px width, confirm nothing is clipped and labels stay attached to fields.
- Error recovery. Submit an invalid form and confirm errors are announced, focusable, and specific.
Pair this with the full WCAG 2.2 checklist and the website audit guide.
Check Your Form in Seconds
Run any page with a form through our free axe-core-powered auditor to catch missing labels, unlabeled controls, and contrast failures — then work through the manual checks above.
Frequently Asked Questions
What makes a form accessible?▾
An accessible form can be perceived, understood, and operated by everyone — including people using a keyboard, a screen reader, voice control, or a screen magnifier. In practice that means every control has a programmatically associated label, the required state and input format are communicated in text (not color alone), validation errors are announced and tied to the field that caused them, related controls are grouped with fieldset and legend, autocomplete tokens are set on personal-data fields, and the whole form can be completed and submitted using only the keyboard. These map directly to WCAG 2.2 success criteria such as 1.3.1, 3.3.1, 3.3.2, 3.3.3, and 4.1.2.
Should I use placeholder text instead of a label?▾
No. A placeholder is not a substitute for a label. Placeholder text disappears as soon as the user starts typing, so it fails users with memory or cognitive disabilities, it is not reliably announced by every screen reader, and its default low-contrast gray often fails WCAG 1.4.3 contrast. Always provide a persistent, visible <label> associated with the input via the for/id relationship. Use the placeholder only for a supplementary example format (for example, MM/YYYY), never for the field name itself.
How do I make form validation errors accessible?▾
Do four things. First, describe the error in specific text (for example, "Enter a valid email address such as name@example.com"), not just a red border. Second, associate the message with its field using aria-describedby so screen readers read it when the field is focused. Third, set aria-invalid="true" on the failed field so assistive tech reports it as invalid. Fourth, when errors appear after submission, move focus to the first invalid field or to an error summary, and expose the summary in an ARIA live region so it is announced. This satisfies WCAG 3.3.1 Error Identification and 3.3.3 Error Suggestion.
When should I use fieldset and legend?▾
Use <fieldset> with a <legend> whenever several controls form a single logical group that needs a shared label. The classic case is a set of radio buttons or checkboxes: the legend ("Shipping method") gives the group its question, and each input keeps its own label ("Standard", "Express"). Screen readers announce the legend together with each option so the choice makes sense out of context. It is also useful for grouping related fields such as a billing address block. This supports WCAG 1.3.1 Info and Relationships.
What is the autocomplete attribute and why does it matter for accessibility?▾
The autocomplete attribute tells the browser (and assistive tech) the semantic purpose of a field — autocomplete="email", "given-name", "tel", "postal-code", and so on. WCAG 2.2 success criterion 1.3.5 Identify Input Purpose requires these tokens on fields that collect the user's own information. They let browsers and password managers autofill accurately, help people with cognitive and motor disabilities avoid re-typing, and allow personalization tools to add familiar icons. It is a small attribute with a large usability payoff, so add it to every personal-data field.
How do I make a required field accessible?▾
Mark it two ways so no single sense is required. Add the required attribute (or aria-required="true" for custom controls) so assistive tech announces "required", and also indicate it visually in the label text — either the word "(required)" or an asterisk whose meaning you explain once at the top of the form. Never rely on color alone or on placeholder-only cues. Tell users up front which fields are mandatory, and prefer marking the few required fields rather than the many optional ones when most fields are needed.
Are HTML5 native form controls better than custom ones for accessibility?▾
Almost always, yes. Native controls — <input>, <select>, <textarea>, <button> — come with built-in keyboard behavior, focus management, form semantics, and screen reader support that you would otherwise have to rebuild with ARIA and get exactly right. Build custom widgets (comboboxes, date pickers, custom selects) only when a genuine requirement can't be met natively, and when you do, follow the ARIA Authoring Practices patterns closely and test with real assistive technology.
Essential Accessibility Resources
Comprehensive tools, checklists, and guides to help you create inclusive digital experiences