Avoid multiple labels on form fields
Last updated:
Related Guides
Form fields must not have multiple labels
Each form control must expose one programmatic label (accessible name).
This issue appears when a single input, select, or textarea is associated with more than one label or name source.
It affects screen reader users, voice control users, and anyone relying on clear, consistent form interactions.
Why It Matters
When more than one label is tied to the same control, assistive technologies can announce different text depending on the browser or AT. Some read the first label, some the last, others combine them. This inconsistency confuses users and slows form completion.
Voice control users may experience mismatches between what is visible and what the system expects them to say, causing commands to fail.
This problem undermines perceivable relationships (WCAG 1.3.1), name/role consistency (WCAG 4.1.2), and clear labeling (WCAG 3.3.2).
Common Causes
- Two or more label elements pointing to the same id via for attributes.
- Wrapping a control in a label while also using a separate label
for="...". - Combining a label element with
aria-labelledbythat references additional nodes as names. - Using both
aria-labeland a label element on the same control. - Adding instructions or status text as extra label elements instead of descriptions.
- Relying on the title attribute as an additional label source.
How to Fix
- Provide exactly one accessible name per control.
- Preferred: one label element associated with the control (either wrapping or using for=). Do not do both.
- Avoid mixing label with
aria-labeloraria-labelledbyunless you intentionally replace the label entirely.
- Move extra text into descriptions, not labels.
- Use
aria-describedbyto attach help text, examples, and error messages. - Keep the label concise; keep guidance in separate elements referenced by
aria-describedby.
- Use
- Group related options correctly.
- For radio or checkbox groups, use fieldset and legend for the group question.
- Give each option one label. Do not add a second label for group instructions.
- Do not use title for required labeling.
- Title is unreliable across platforms and should not be the main label.
- Validate associations.
- Each control’s id should match at most one label’s for attribute, or be wrapped by one label—not both.
- Remove any redundant
aria-labelledbyoraria-labelwhen a label element is present.
Recommendation: If you must compute a name from multiple text nodes, use aria-labelledby alone and omit the label element to avoid multiple name sources. Ensure the visible text matches the computed accessible name.
How to Test
Keyboard check
- Tab through all fields. Each field should receive focus once, and pressing a label should toggle/activate only its associated control.
Screen reader check
- With NVDA or JAWS (Windows) and VoiceOver (macOS/iOS) or TalkBack (Android), navigate by form fields.
- Each control announces one clear label plus the control type (e.g., “Email, edit”). No duplicated or conflicting label text.
Mobile/touch check
- Tap labels. Only the intended control activates or toggles.
- Screen reader does not repeat multiple labels for the same control.
Quick automated check
- Run an automated scanner (e.g., axe, Accessibility Insights) to flag multiple labels or conflicting name sources.
Good Example
<label for="email">Work email</label>
<div id="email-hint">Use your company address.</div>
<input id="email" name="email" type="email" aria-describedby="email-hint email-error" aria-invalid="false">
<!-- Error message is injected on validation when needed -->
<div id="email-error" class="visually-hidden" aria-live="polite"></div>
<fieldset>
<legend>Preferred contact method</legend>
<div>
<input type="radio" id="contact-email" name="contact" value="email">
<label for="contact-email">Email</label>
</div>
<div>
<input type="radio" id="contact-phone" name="contact" value="phone">
<label for="contact-phone">Phone</label>
</div>
</fieldset>Bad Example
<!-- Two labels pointing to the same input -->
<label for="user">Username</label>
<label for="user">Account ID</label>
<input id="user" type="text">
<!-- Mixed nested label and for= label on the same control -->
<label for="tos">Terms of Service</label>
<label><input id="tos" type="checkbox"> I accept the terms</label>
<!-- Label plus aria-labelledby creating multiple name sources -->
<label id="city-label" for="city">City</label>
<span id="city-extra">(required)</span>
<input id="city" type="text" aria-labelledby="city-label city-extra">Quick Checklist
- Exactly one label source per control (label OR aria-*), not both.
- Use label for the primary name; use
aria-describedbyfor help, examples, and errors. - Do not wrap and for= the same control at once.
- No duplicate label elements targeting the same id.
- For groups of radios/checkboxes, use fieldset/legend plus one label per option.
- Avoid title as a label; it is not reliable.
- Screen readers announce one clear label and the correct control type.
- Automated tests show no multiple labels or conflicting accessible names.