Accessible Forms Guide - Build Forms Everyone Can Complete
Accessible forms are forms that everyone can understand, fill in and submit, including people who use screen readers, keyboards, voice control, magnification or who have cognitive disabilities. Forms are where visitors sign up, buy, book and contact you, so an inaccessible form directly costs you customers. The good news is that most problems come from a handful of fixable mistakes: missing labels, unclear errors, and fields that fight the user.
This guide walks through the WCAG requirements for accessible forms, with code examples and a testing checklist.
Why accessible forms matter
A form can look fine and still be unusable. A screen reader user may hear "edit text, edit text, edit text" with no idea what each field is for. A keyboard user may be unable to reach a custom dropdown. Someone with a memory impairment may be locked out by a login that demands they recall and retype a complex code. Each of these is a lost signup or sale, and form failures are among the most common issues found in accessibility audits.
Labels: the foundation of accessible forms
Every input needs a visible label that is programmatically connected to it. This supports WCAG 1.3.1 Info and Relationships (level A) and 3.3.2 Labels or Instructions (level A).
<label for="email">Email address</label>
<input id="email" name="email" type="email">
Clicking the label then focuses the field, which also creates a bigger click target.
Do not rely on placeholders
Placeholder text disappears when the user starts typing, often has low contrast, and is not a reliable label. Use it only for short hints, if at all. Check placeholder and label colours against our color contrast guide.
Group related fields with fieldset and legend
Radio buttons and checkbox groups need a group label so screen reader users know what question they are answering.
<fieldset>
<legend>Preferred contact method</legend>
<input type="radio" id="c-email" name="contact" value="email">
<label for="c-email">Email</label>
<input type="radio" id="c-phone" name="contact" value="phone">
<label for="c-phone">Phone</label>
</fieldset>
Required fields and input formats
Tell users up front what is required and what format you expect.
- Mark required fields in the visible label, for example "Name (required)", or explain at the top that fields marked with an asterisk are required.
- Add the
requiredattribute so assistive technology announces it. - Give format hints before the field, not only after an error, and connect them with
aria-describedby.
<label for="dob">Date of birth (required)</label>
<p id="dob-hint">For example, 27 03 1990</p>
<input id="dob" name="dob" required aria-describedby="dob-hint">
Better still, accept many formats. Strip spaces and dashes from phone and card numbers instead of rejecting them.
Error identification and suggestions
When something goes wrong, users need to know which field, what is wrong, and how to fix it.
| Criterion | Level | What it requires |
|---|---|---|
| 3.3.1 Error Identification | A | Errors are identified and described to the user in text |
| 3.3.3 Error Suggestion | AA | If a fix is known, suggest it |
| 3.3.4 Error Prevention (Legal, Financial, Data) | AA | Submissions can be reversed, checked or confirmed |
Writing helpful error messages
- Bad: "Invalid input."
- Better: "Enter an email address in the format name@example.com."
- Do not rely on colour alone. A red border needs a text message and, ideally, an icon.
Connecting errors to fields
<label for="email">Email address</label>
<input id="email" type="email" aria-invalid="true"
aria-describedby="email-error">
<p id="email-error">Enter an email address, like name@example.com</p>
For long forms, show an error summary at the top after submission, with links to each problem field, and move focus to that summary so screen reader users hear it.
Error prevention
For forms involving money, legal commitments or deleting data, give users a review step, a confirmation checkbox, or a way to undo. A "Review your order" page before payment is a simple and familiar pattern.
Autocomplete and input purpose (1.3.5)
WCAG 1.3.5 Identify Input Purpose (level AA) asks you to mark common personal data fields so browsers and assistive tools can fill them in or show familiar icons.
<input id="fname" name="fname" autocomplete="given-name">
<input id="email" type="email" autocomplete="email">
<input id="tel" type="tel" autocomplete="tel">
<input id="addr" autocomplete="street-address">
Autofill helps people with motor and cognitive disabilities enormously, and it speeds up checkout for everyone. Using the correct type values (email, tel, number when appropriate) also brings up the right mobile keyboard.
New in WCAG 2.2: redundant entry and accessible authentication
3.3.7 Redundant Entry (level A)
Do not make users type the same information twice in one process. If a customer entered a delivery address, offer a "Billing address is the same" checkbox or pre-fill it. Exceptions exist for security, such as re-entering a new password, and when the earlier information is no longer valid.
3.3.8 Accessible Authentication (Minimum) (level AA)
Login steps should not require a cognitive function test, such as remembering a password or solving a puzzle, unless there is an alternative or help. In practice:
- Allow paste into password and code fields, and do not block password managers.
- Support
autocomplete="current-password"andautocomplete="one-time-code". - Offer alternatives like email magic links or passkeys.
<label for="pw">Password</label>
<input id="pw" type="password" autocomplete="current-password">
CAPTCHA alternatives
Traditional image and distorted-text CAPTCHAs are a serious barrier for blind users and people with cognitive or visual disabilities. Audio versions help some users but not all. Consider less intrusive options:
- Honeypot fields hidden from humans that bots tend to fill in.
- Server-side rate limiting and spam filtering.
- Invisible or risk-based checks that only challenge suspicious traffic.
- Email or SMS verification where appropriate.
If you must use a CAPTCHA, provide at least two different modes, such as visual and audio, and a way to contact support.
Target size and layout
WCAG 2.5.8 Target Size (Minimum), new in 2.2, sets a 24 by 24 CSS pixel minimum for pointer targets, with exceptions such as when there is enough spacing. Small checkboxes and radio buttons are the usual offenders. Because clicking a properly connected label also activates its control, labels effectively enlarge the target. Other layout tips:
- Use a single column for most forms; it is easier to scan and zoom.
- Keep labels above or directly beside their fields.
- Make sure the form still works at 200% zoom and on narrow screens.
- Ensure every field and button can be reached with Tab in a logical order; see our keyboard accessibility guide.
A full accessible form example
<form novalidate>
<p>All fields are required unless marked optional.</p>
<label for="name">Full name</label>
<input id="name" name="name" autocomplete="name" required>
<label for="email">Email address</label>
<input id="email" name="email" type="email"
autocomplete="email" required>
<label for="msg">Message (optional)</label>
<textarea id="msg" name="msg"></textarea>
<button type="submit">Send message</button>
</form>
Note the real button element, clear text, and autocomplete values.
How to test accessible forms
- Automated scan. Run the page through our free accessibility checker; it flags missing labels and controls without accessible names, with how-to-fix tips.
- Keyboard test. Complete and submit the form with no mouse.
- Error test. Submit it empty and with wrong data. Are errors clear, in text, and linked to fields?
- Screen reader test. Listen to each field's name, state and hint. Our screen reader testing guide explains how.
- Zoom and mobile test. Check at 200% zoom and on a phone.
Some visitors also benefit from personalisation tools. The Openwise widget includes a form helper alongside features like bigger text and keyboard focus outlines, but it supports good form code rather than replacing it. Work through our WCAG checklist for the remaining criteria.
Frequently asked questions
What makes a form accessible?
An accessible form has a visible, programmatically connected label for every field, groups related options with fieldset and legend, explains required fields and formats up front, shows clear text error messages linked to fields, works fully with a keyboard, and supports autofill. These cover the core WCAG requirements for forms.
Are placeholders enough as labels?
No. Placeholder text disappears when typing begins, often has poor contrast, and is not consistently announced by assistive technology. Use a real label element for every field and keep placeholders for optional short hints.
How should error messages be announced to screen readers?
Link each error to its field with aria-describedby and set aria-invalid="true". For longer forms, show an error summary at the top after submission and move focus to it so it is read out. You can also use a live region to announce errors without moving focus.
Do I need to stop using CAPTCHA?
Not necessarily, but traditional visual CAPTCHAs exclude many users. Prefer honeypots, rate limiting or risk-based checks. If you keep a CAPTCHA, offer more than one mode and a way to get help, and remember WCAG 3.3.8 limits cognitive tests in login flows.
What do WCAG 2.2 changes mean for forms?
WCAG 2.2 added 3.3.7 Redundant Entry, so you should not ask for the same information twice in a process, and 3.3.8 Accessible Authentication (Minimum), which means allowing password managers and paste, or offering alternatives to memory tests. It also added 2.5.8 Target Size (Minimum) for small controls.
Conclusion
Accessible forms are not hard to build: label every field, explain what you need, write useful errors, support autofill, and avoid making people remember or retype things. Each fix makes your forms faster for every user, not just disabled users. Start by scanning your signup, contact and checkout pages with our free accessibility checker and fixing what it finds.
Is your website accessible?
Run a free WCAG check, or add the Openwise widget with one line of code.
Check my website Get started free