form-control-single-label

Form controls should not have multiple labels

automaticWCAG 3.3.2 (A)confidence: highseverity: moderateunderstandable

Checks that a form control is associated with at most one <label> (by wrapping or by label[for]).

Applies to. Applies to labelable form controls (input, excluding hidden/submit/reset/button/image; select; textarea).

Expectation. At most one <label> that can contribute to the control's accessible name is associated with it, as HTML's labeled control defines: a <label for="..."> whose value is the id of the first element with that id in the label's own tree, or a wrapping <label> without for whose first labelable descendant is the control (a label that both wraps and self-references via for counts once). Graded by whether the surplus labels actually compete for the name:

  • PASS when an override (aria-labelledby / aria-label) supersedes every native <label>: the labels then contribute nothing to the name, so they cannot be ambiguous. A visible-label-vs-name mismatch is SC 2.5.3 Label in Name's concern, not this rule's.
  • CANTTELL when two or more non-empty labels compete and there is no override: browsers join their text, in DOM order, into one name, and only a person can tell whether that joined name still makes sense ("Address Mailing address") or reads as noise.
  • CANTTELL when one non-empty label is joined by empty label association(s) and there is no override: the name usually resolves to the real label, but handling of the empty association is not guaranteed across user agents.

All-empty associations with no override are a missing-name case (the sibling rule form-control-programmatic-label-present), not an ambiguity, so this rule stays silent.

What a finding reports.

  • labelCount: how many labels are associated with the control. On the competing-labels case, only the non-empty ones are counted; on the empty-label case, the empty ones are counted too.
  • contributingLabelCount (the empty-label case): how many of those labels have text, and so give the control its name.

These data.details fields help to read and reproduce a finding. Apart from reasonCode and the few fields Output schema names as stable, they are not a stable contract: a field may be renamed or dropped in a minor release, so don’t build on them.

Examples

pass
<label>Name <input type="text"></label>

A single wrapping label; only one labelling mechanism applies.

can't tell
<label for="address">Address</label>
<label for="address">Mailing address</label>
<input id="address" type="text">

Two separate label[for] elements both target the same control. Browsers join them into one name, "Address Mailing address", and only a person can tell whether it still reads well.

How to check

When this rule can’t decide, it reports cantTell and leaves the question to a person. Each question it can ask is listed here under its reason code, with the steps to answer it. A finding carries the same steps as howToCheck, in the scan’s language. See Output schema.

FORM_FIELD_EXTRA_EMPTY_LABEL

  1. Find the field the report names and note its label with text and the empty label also pointing at it.
  2. Open the Accessibility pane in the browser's developer tools and check that the field's name is the text of the real label.
  3. With a screen reader, Tab to the field and listen to the name.

Pass. The field's name is the text of the real label, and nothing is lost to the empty one.

Fail. The field gets no name or an incomplete one because of the empty label, which fails WCAG 3.3.2 (and 4.1.2).

FORM_FIELD_MULTIPLE_LABELS

  1. Find the field the report names and note the text of each label pointing at it.
  2. Open the Accessibility pane in the browser's developer tools and read the field's accessible name, which joins all the labels.
  3. With a screen reader, Tab to the field and listen to the name.
  4. Decide whether the joined name still says clearly what to enter.

Pass. The joined name is clear: the labels repeat each other or the extra one is only a marker such as "required".

Fail. The joined name is confusing or misleading, such as two unrelated labels run together, which fails WCAG 3.3.2 (and can fail 2.5.3 and 4.1.2).

View source