form-control-programmatic-label-quality
Form controls should have a label shown on screen
Flags form controls whose accessible name comes from placeholder, title, aria-label, or aria-labelledby pointing only at hidden text, none of which is a label shown on screen. Prefer a visible <label>, or aria-labelledby pointing at visible text.
Applies to. Applies to labelable native form controls exposed to assistive technologies:
- input (excluding type=hidden|submit|reset|button|image)
- select
- textarea
role="presentation"/"none" are excluded only when not focusable. A control not drawn on screen is excluded: transparent (opacity 0, its own or an ancestor's) or clipped away (as visually hidden text is), as a checkbox hidden behind a styled toggle is. It has no visible label to judge; its visible stand-in does. Only controls that have a programmatic name count: a control with none is form-control-programmatic-label-present's finding, not a question about how good its name is.
Expectation. If a control has a programmatic name, it should not come ONLY from:
- placeholder (non-empty)
- title (non-empty)
- aria-label
- aria-labelledby whose every referenced element is unrendered (hidden, display:none, visibility:hidden)
Prefer an associated <label> or aria-labelledby pointing at visible text.
What a finding reports.
labelMethod: where the control's label comes from:placeholder,title,aria-labeloraria-labelledby.reasonCode:label_from_placeholder_primary,label_from_title_primary,label_from_aria_label_onlyorlabel_from_hidden_labelledby.sourceText: the label text, up to 120 characters.
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
<label for="email">Email address</label><input type="text" id="email" placeholder="name@example.com">
A persistent <label> provides the name; placeholder is just a format hint here.
<input type="text" placeholder="Email address">
The control's only name comes from placeholder, which disappears once the user starts typing.
<input type="text" title="Name">
The control's only name comes from title, which is shown only on hover. Both give the control a name, so WCAG 4.1.2 is met; what is missing is a label shown to everyone, which is SC 3.3.2.
<input type="search" aria-label="Search">
The control's only name comes from aria-label, which is never shown on screen. Visible text next to the field, such as a search button, may still tell sighted users what it is for, so this needs a look rather than a fail.
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.
label_from_aria_label_only
- Find the field the report names on screen and read its aria-label, which the report gives.
- Look for text shown next to the field (a visible label, a heading or a legend) that tells what to enter.
Pass. Text shown next to the field, or an icon whose meaning is plain such as a magnifier on a search field, tells what to enter.
Fail. Nothing shown on screen tells what to enter in the field, which fails WCAG 3.3.2.
label_from_hidden_labelledby
- Find the field the report names and, in the developer tools, follow its aria-labelledby ids to the elements they point at.
- Check whether those elements are shown on screen when the field is.
- Look for other text shown next to the field that tells what to enter. A button right after the field that says what it does, such as Search after a search field, also counts.
Pass. The labelling text is shown with the field, or other text next to it, or a button right after it such as Search, tells what to enter.
Fail. The label is only in hidden elements and nothing on screen tells what to enter, which fails WCAG 3.3.2.
label_from_placeholder_primary
- Find the field the report names and read its placeholder.
- Type something in the field.
- Check whether anything still shown on screen tells what the field is for: a label or text next to it. A button right after the field that says what it does, such as Search after a search field, also counts.
Pass. A label, text next to the field, or a button right after it such as Search stays on screen once the field is filled in and tells what to enter.
Fail. Once the field is filled in, nothing on screen tells what it is for, which fails WCAG 3.3.2.
label_from_title_primary
- Look at the field the report names without hovering over it.
- Look for text shown next to it that tells what to enter. A button right after the field that says what it does, such as Search after a search field, also counts.
- Tab to the field with the keyboard and note that its title tooltip does not appear.
Pass. Without hovering, text next to the field, or a button right after it such as Search, tells what to enter.
Fail. What to enter is told only by the title, shown on mouse hover, so keyboard and touch users never see it, which fails WCAG 3.3.2.