One control, two labels: why multiple labels confuse
A control with two labels is announced inconsistently across screen readers. squirrel counts the labels on every input on the page.
What multiple labels means
A form control has one accessible name. When two <label> elements point at the same control, HTML says the name is the label texts concatenated in document order, which is legal and usually unhelpful: the user hears both strings run together, in whatever order the markup happens to be in.
Extra text about a field is a description, not a second name. That is what aria-describedby is for, and screen readers announce it after the name rather than fighting with it.
What squirrel checks
One check, form-field-multiple-labels, at severity warning. It covers every <input> except types hidden, submit, button and reset, plus every <textarea> and <select>.
For each control it counts every <label for="..."> whose value matches the control’s id, and adds one when the control has an ancestor <label>.
- Warn when the count is more than one. Report message:
N input(s) with multiple labels. Items reademail (2 labels), naming the control by itsname, falling back to itsidand then its tag. Every offender is listed, and the finding carries the suggestionUse aria-describedby for additional descriptions. - Pass with
No inputs have multiple labels. - Info with
No form inputs found.
How to fix it
<label for="pw">Password</label>
<input id="pw" type="password" aria-describedby="pw-hint">
<p id="pw-hint">At least 12 characters, including a number.</p>Keep one label and move the rest into aria-describedby. The description can point at several ids, so a hint and an error message can coexist.
A control wrapped in a <label> that also has a separate <label for> pointing at it is the usual shape, and it usually arrives when a wrapper is added for click-target reasons. Removing the wrapper <label> and keeping the explicit association fixes both.
| Rule ID | a11y/form-field-multiple-labels |
| Category | Accessibility |
| Scope | Per-page |
| Severity | warning |
| Weight | 5/10 |
Enable / disable
Disable this rule
[rules]
disable = ["a11y/form-field-multiple-labels"]Disable all Accessibility rules
[rules]
disable = ["a11y/*"]Enable only this rule
[rules]
enable = ["a11y/form-field-multiple-labels"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- a11y/form-labels: controls with no label at all.
- a11y/duplicate-id-active: a duplicated id, which sends a
<label for>to the first match and leaves the control you meant unlabeled. - a11y/label-content-name-mismatch: a label that disagrees with the visible text.
- a11y/aria-input-field-name: the resolved name once the labels are sorted out.
Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Accessibility section of the report. Each control is listed with the number of labels pointing at it. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.