Accessible Forms: Labels, Errors, Required Fields, and Instructions
Forms are where most users convert. They are also where the most consequential accessibility failures hide, completely invisible in a visual browser tes..
Forms are where most users convert. They are also where the most consequential accessibility failures hide, completely invisible in a visual browser test.
Video: Accessible Forms: Labels, Errors, Required Fields, and Instructions
A missing label renders an input field nameless to a screen reader. A dynamically injected error message announces nothing unless you have told the DOM to announce it. A required field marked only by a red asterisk communicates nothing to a user who cannot see colour. These are not obscure edge cases. They are the default output of major form libraries when used without accessibility intent, and they block task completion entirely, not just content consumption.
This article gives you the implementation framework for the four components that determine whether a form works for assistive technology users: labels, error messages, required fields, and instructions. Before you start a manual audit, run an automated baseline with our free website accessibility checker to flag the markup gaps that are hardest to catch in code review.
Why Forms Fail Accessibility – and Why It Costs More Than Other Failures
An inaccessible paragraph is a problem. An inaccessible form is a wall.
When a content element fails accessibility, users miss information. When a form element fails, users cannot complete the action. They cannot submit a contact enquiry, finish checkout, or create an account. The failure is total and immediate. There is no workaround.
That stakes differential is why form accessibility deserves its own implementation discipline. Most accessibility failures affect content consumption. Form failures affect task completion.
The legal framing is brief: according to ADA.gov’s guidance on web accessibility, ADA Title III covers private businesses and has no government-mandated compliance deadline for web accessibility. Enforcement is lawsuit-driven, and courts consistently apply WCAG 2.1 AA as the de facto standard. Inaccessible forms are exactly the kind of concrete barrier that triggers complaints. If you are selling into the EU, the European Accessibility Act came into force on June 28, 2025. Forms are in scope.
The four components this article covers are labels, error messages, required fields, and instructions. Get these right and you eliminate the majority of form-level accessibility failures before they ship.
The Four Form Components That Make or Break Accessibility
Every accessible form is built on four structural decisions.
Labels connect an input to its name. Without a correctly associated label, a screen reader user tabs to a field and hears “edit text” and nothing more.
Error messages tell users what went wrong and how to fix it. Without accessible error handling, a failed submission is silent. The user knows something is wrong only if they can see the visual state change.
Required fields communicate which inputs must be completed before submission. Without accessible required-field markup, users discover requirements only after failing.
Instructions tell users what format or content you expect. Without accessible hint text, users guess, and the errors that follow circle back into broken error message flows.
These four components are interdependent. Fix labels but not errors, and a user with a screen reader can navigate your form but cannot recover from mistakes. Fix all four and the form works end-to-end for keyboard users, screen reader users, and users with cognitive disabilities.
Labels: The One Rule That Eliminates Most Form Failures
WCAG criteria: 1.3.1 (Info and Relationships, Level A) and 2.4.6 (Headings and Labels, Level AA).
WCAG 1.3.1 requires that the relationship between a label and its input is programmatically determinable, not just visually obvious. WCAG 2.4.6 requires that labels are descriptive. Both must pass.
The correct patterns
Visible <label> with for/id association. This is the baseline. Use it everywhere you can.
<label for="email">Email address</label>
<input type="email" id="email" name="email">
The for attribute value must match the input’s id exactly. This is the most reliable pattern across all browsers and assistive technologies.
aria-labelledby – use when the label text already exists in the DOM as a visible heading or adjacent text element and you cannot restructure the markup.
<h2 id="billing-heading">Billing address</h2>
<input type="text" aria-labelledby="billing-heading" ...>
aria-label – use sparingly, for inputs where a visible label would be visually redundant (a search field inside a search landmark, for example). The label exists in the accessibility tree but not in the visual UI.
<input type="search" aria-label="Search products">
aria-label has no visible text, which creates problems for users who rely on speech recognition software to interact by speaking field names. Prefer visible labels.
The most common wrong pattern: placeholder as label
Do not use placeholder as a substitute for <label>. This fails WCAG 1.3.1 and 3.3.2 simultaneously.
Placeholder text disappears the moment a user starts typing. A user who pauses mid-form to check a detail loses the field’s label entirely. Placeholder contrast also fails WCAG 1.4.3 in most browser defaults. Placeholder text is hint text. Treat it as such.
The correct approach: provide a visible <label> and use placeholder only for supplementary format examples.
Keyboard-only users depend on correct label association too. Focus management and the accessible name announced on focus both rely on it. See Keyboard Accessibility: Test Your Site in 5 Minutes for the keyboard testing layer.
Error Messages: How to Tell Users What Went Wrong and How to Fix It
WCAG criteria: 3.3.1 (Error Identification, Level A) and 3.3.3 (Error Suggestion, Level AA).
WCAG 3.3.1 requires that when a user makes an input error, the item in error is identified and the error is described in text. WCAG 3.3.3 requires that if the error can be corrected, the suggestion is provided, unless doing so would jeopardise security or purpose.
A useful error message contains three things: identification (which field failed), description (what the error is), and suggestion (how to fix it). “Invalid input” fails 3.3.3. “Enter a valid email address in the format name@example.com” passes.
Inline validation errors
Inline errors appear adjacent to the failing field. The correct pattern associates the error message with the input using aria-describedby:
<label for="email">Email address</label>
<input type="email" id="email" aria-describedby="email-error" aria-invalid="true">
<span id="email-error" role="alert">Enter a valid email address, for example name@example.com</span>
aria-invalid="true" signals to AT that the field is in an error state. aria-describedby connects the error text to the input so that when focus lands on the field, the error is read alongside the label.
Dynamic error injection: the critical detail
Injecting an error message into the DOM after submission does not announce anything to a screen reader unless you explicitly handle the announcement.
Two reliable approaches:
- Give the error container
aria-live="assertive"before the error is injected. When content is added to a live region, AT announces it automatically.
<span id="email-error" aria-live="assertive"></span>
- Move focus programmatically to the first error field or to an error summary panel after submission. Focus movement triggers a read-out.
Without one of these two mechanisms, a screen reader user submits the form, nothing happens audibly, and they have no way to know whether the submission succeeded or failed.
Error summary panels
For longer forms, an error summary panel at the top of the form, listing all errors with links to the failing fields, is a valid and often better pattern than inline-only errors. The panel must have aria-live="assertive" or receive focus after submission. Each item in the summary should link directly to the relevant input.
On short forms, inline errors with aria-describedby are usually sufficient. On multi-section or multi-step forms, an error summary panel is more usable. Both patterns are valid; both have different implementation implications.
If your error markup is missing aria-live regions or aria-describedby connections, an automated scan will flag the structural gaps. Run the free website accessibility checker against your form pages specifically.
Required Fields: Three Ways to Mark Them and When to Use Each
WCAG criterion: 3.3.2 (Labels or Instructions, Level A).
WCAG 3.3.2 requires that if an input requires specific information, that requirement is communicated before the user makes an error. For required fields, this means users must know a field is required before they attempt submission.
There are three valid approaches.
1. Visual asterisk with a legend
The most common pattern. A note at the top of the form declares that asterisks denote required fields; the asterisk is added to each required label.
<p>Fields marked with <span aria-hidden="true">*</span> <span class="sr-only">an asterisk</span> are required.</p>
<label for="name">Full name <span aria-hidden="true">*</span></label>
<input type="text" id="name" required>
The asterisk itself should be hidden from AT with aria-hidden="true" to avoid reading “asterisk” mid-label. The legend at the top explains the convention. The required attribute handles programmatic enforcement.
2. aria-required="true"
Use aria-required="true" when you cannot use the native required attribute, for example in custom UI components that do not map to native form elements.
<div role="textbox" aria-required="true" aria-labelledby="name-label">
Most modern screen readers announce “required” when focus reaches a field with aria-required="true". Note that aria-required does not trigger native browser validation the way required does. If you use custom components with role="textbox" or similar, aria-required is the correct mechanism.
3. HTML required attribute
For native HTML inputs, required is the preferred attribute. It triggers browser-native validation, is announced by screen readers as “required,” and provides a built-in constraint before form submission. Combine it with the visual asterisk pattern for full coverage.
The most important rule: never communicate required status through colour alone. A red label or red border with no text-based indicator fails WCAG 1.4.1 (Use of Colour) and fails users who are colour-blind or using high-contrast mode.
Instructions and Hint Text: Telling Users What You Expect Before They Make a Mistake
WCAG criterion: 3.3.2 (Labels or Instructions, Level A).
Instructions that appear only after an error is made do not satisfy WCAG 3.3.2. The requirement is that instructions are present before the user submits.
Form-level instructions
If the form has constraints that apply globally, such as “all fields are required unless marked optional” or “use your legal name as it appears on your ID,” state these before the first input, not after the submit button. Reading order matters. Instructions placed after the fields they apply to are encountered too late by users navigating sequentially with a keyboard or screen reader.
Field-level hint text with aria-describedby
For individual field constraints, date format, password requirements, character limits, use aria-describedby to connect the hint to the input:
<label for="dob">Date of birth</label>
<span id="dob-hint">Use the format DD/MM/YYYY</span>
<input type="text" id="dob" aria-describedby="dob-hint">
The hint element must be present in the DOM and visible (or at minimum available to AT) before the user enters the field. Do not inject hint text only on focus or only on error. That is a 3.3.2 failure.
When a field has both hint text and an error message, chain both IDs in aria-describedby:
<input type="text" id="dob" aria-describedby="dob-hint dob-error">
AT will read both, in order.
Seven Mistakes Developers Ship by Accident
These are the patterns that pass visual QA and fail AT testing.
1. Placeholder as label. It appears constantly in React and Vue component libraries by default. It fails WCAG 1.3.1 and 3.3.2 simultaneously. Replace with a visible <label>.
2. aria-label on the container, not the input. Wrapping a form group in a <div aria-label="..."> does not label the inputs inside it. The aria-label must be on the element that receives focus: the <input>, <select>, or <textarea>.
3. Dynamically injected errors with no live region and no focus management. Without aria-live="assertive" or programmatic focus movement, the error is invisible to screen reader users.
4. Required fields communicated only by colour. A red border or red label text with no text-based indicator fails WCAG 1.4.1. If your design system uses colour to indicate required state, add a text marker or aria-required="true". See Color Contrast Checker: How to Find and Fix Low Contrast for related visual accessibility issues.
5. Hint text injected after focus, not before. If hint text appears only when a user focuses a field via JavaScript, users navigating by keyboard or virtual cursor may not encounter it in reading order. Hint text should be present in the DOM on page load.
6. Error messages that identify the error but not the fix. “This field is required” satisfies 3.3.1 but not 3.3.3. If the correction is not security-sensitive, tell the user how to fix it.
7. Multi-step forms that destroy error state between steps. If a user navigates back in a multi-step form and previously entered values or error associations are cleared, the form fails 3.3.4 (Error Prevention). Preserve state between steps and re-associate errors correctly on re-render.
If you are selling into the EU: the European Accessibility Act came into force on June 28, 2025, applying WCAG 2.1 AA requirements to any company with 10+ employees or €2M+ turnover selling into EU markets. Form failures are directly in scope.
This article is for general informational purposes and is not legal advice.
Form Accessibility QA Checklist
Use this during code review and before release. Automated checks first, then keyboard, then AT.
Automated checks
- [ ] Every
<input>,<select>, and<textarea>has an associated<label>(viafor/id),aria-label, oraria-labelledby - [ ] No input relies solely on
placeholderas its label - [ ] Error message containers that receive dynamically injected content have
aria-live="assertive"oraria-live="polite"set before injection - [ ] Error messages are connected to their inputs via
aria-describedby - [ ]
aria-invalid="true"is present on all inputs in an error state - [ ] Required fields use
requiredoraria-required="true", not colour alone - [ ] Hint text elements referenced by
aria-describedbyare present in the DOM on page load
Keyboard verification
- [ ] Tab moves through all inputs in logical reading order
- [ ] Each focused input announces its label and any associated hint text or error
- [ ] Form can be submitted with the keyboard (Enter on a submit button)
- [ ] After a failed submission, focus moves to the first error field or to an error summary panel
- [ ] No keyboard trap is introduced by custom dropdowns, date pickers, or modal overlays within the form
Screen reader verification
- [ ] Each input announces its label when focused (no “unlabelled” or “edit text” without a name)
- [ ] Required fields are announced as “required” on focus
- [ ] Error messages are announced immediately after a failed submission, either via live region or focus movement
- [ ] Hint text is read after the label when focus enters the field
- [ ] Error summary panel (if used) is announced and links navigate correctly to the failing fields
- [ ] Multi-step forms announce the current step and restore field state correctly on back navigation
For the full screen reader testing protocol across NVDA, JAWS, and VoiceOver, see Screen Reader Testing: Beginner Checklist for NVDA, JAWS, and VoiceOver.
Once you have this checklist in hand, run your form pages through the free website accessibility checker to validate your markup against the automated criteria above. The scanner flags missing label associations, absent live regions, and aria-invalid gaps: exactly the structural issues that are invisible in a visual browser test.