label-in-name

Label in Name: accessible name contains visible text

automaticWCAG 2.5.3 (A)confidence: highseverity: seriousoperable

Checks that when a control has a visible text label, the accessible name contains that visible label text.

Applies to. Applies to controls named by aria-label or aria-labelledby, are visually rendered, and have visible label text this engine can extract deterministically, from an associated <label>, from the control's own rendered text, or from the elements aria-labelledby points at. The candidates are <button>, <a href>, <summary>, non-hidden form controls, and elements whose role attribute resolves (its first known, non-abstract token, in any case) to the button, link, checkbox, radio, switch, searchbox, tab, menuitem, menuitemcheckbox, menuitemradio, option, treeitem or gridcell role, and a <td> with no role attribute in a grid or treegrid, a gridcell by HTML-AAM, minus anything hidden or disabled. A button-type <input> (submit, reset, button) with a value shows that value as its label; without one it shows the browser's own default, which can't be known, and is out of scope. The visible label is the visible inner text: text in inline elements joins as written (<b>Down</b>load reads "Download"), a block-level box or a <br> starts a new word, and text in a box nobody can see (clipped away, 1x1 px or fully transparent, as screen-reader-only text is) is left out, as are the options of a <select> and the text of a <textarea>, which are a field's value, not label text. aria-hidden is not excluded: it changes nothing about what is rendered on screen, which is what this SC is about. An aria-label that is empty once trimmed, or an aria-labelledby whose ids point at nothing or only at elements with no text, names nothing: the accessible name then comes from the next source (the content, a <label>, title...), as for a control without them, so the control is out of scope. A custom element whose ElementInternals give it one of those roles (this.attachInternals().role), with no role attribute naming another, counts as a native element with that role does.

Expectation. The accessible name contains the visible label's words, adjacent and in order. In a browser, the label is also read as it shows: two boxes drawn side by side on one line with no space between them join their words (flex items "sure" and "a11y" read "surea11y"), and a name that holds either reading contains the label. The comparison is over words rather than characters: parenthesised text is dropped, case is folded, text is NFKC-normalised, and every character that is not a letter, digit or combining mark becomes a separator, so punctuation and spacing differences never decide the outcome. Invisible formatting characters (a soft hyphen, a zero-width space) and an apostrophe inside a word are removed instead, so "Down&shy;load" is "Download" and "Don’t" is "Dont". Accents are not folded: "Déposer" stays one word, and a name that drops an accent ("Deposer") does not contain it. Four shapes markup cannot settle are reported as cantTell instead of fail: a word hyphenated differently in the two places; a visible word the author may have abbreviated, marked by its trailing period; visible text rendered through a known icon font (the DOM text is real words, but nothing readable actually renders); and a whole visible label of exactly one character that doesn't even appear inside the accessible name, which per ACT 2ee8b8 may be "non-text content" (e.g. "X" meaning "close") rather than literal text.

What a finding reports.

  • visibleLabel, accessibleName: the visible label text and the accessible name, as found.
  • normalized.visibleLabel, normalized.accessibleName: the same two texts as compared: parenthesised text dropped, case folded, Unicode normalised.
  • tokenized.visibleLabel, tokenized.accessibleName: the words each text was split into, one word per item. The name must hold the label's words next to each other and in order.
  • Each text is cut at 2,000 characters, with "…" after it, as an occurrence's html is, and each word list at its first 200 words.
  • labelSource: where the visible label came from: label (an associated <label>), self (the control's own text), value (a button-type <input>'s value) or aria-labelledby (the elements it points at).
  • nameMechanism: what gives the accessible name: aria-label or aria-labelledby.

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
<button aria-label="Save changes">Save</button>

The accessible name ("Save changes") contains the visible text ("Save").

fail
<button aria-label="Submit form">Save</button>

The accessible name doesn't contain the visible label text at all.

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.

HYPHENATION_DIFFERS

  1. Read the visible label of the control the report names.
  2. Open the Accessibility pane and read the control's accessible name.
  3. Compare the two: they differ only in where hyphens fall ("e-mail" against "email"); decide whether a person saying the visible label would say the same words.
  4. If speech input software is available, say the visible label and see whether it activates the control.

Pass. The name says the same words as the label, with only the hyphenation differing, so speaking the label reaches the control.

Fail. The hyphenation changes the words, so the name does not contain what the label shows, which fails WCAG 2.5.3.

POSSIBLE_ABBREVIATION

  1. Read the visible label of the control the report names, and note the word ending in a period.
  2. Open the Accessibility pane and read the control's accessible name.
  3. Decide whether the label's word is a common abbreviation of the word in the name ("Ave." for "Avenue") that a person would read aloud as the full word.

Pass. The abbreviation is a conventional one read as the full word that the name contains.

Fail. The label's word is not read as the word in the name, so a person saying the label would not match the name, which fails WCAG 2.5.3.

POSSIBLE_ICON_FONT_GLYPH

  1. Look at the control the report names on screen and note what it shows: readable words or an icon.
  2. Open the Accessibility pane and read the control's accessible name.
  3. If the control shows only an icon, decide whether the name describes it; if it shows readable words, check that the name contains them.

Pass. The control shows an icon rather than readable text, or the readable text it shows is contained in the name.

Fail. The control shows readable words that the accessible name does not contain, which fails WCAG 2.5.3.

POSSIBLE_SYMBOLIC_CHARACTER

  1. Look at the single character the control the report names shows.
  2. Open the Accessibility pane and read the control's accessible name.
  3. Decide whether the character is a symbol standing for an action (an "X" for close, an arrow) or literal text a user would say, such as a digit or letter.

Pass. The character is a symbol, and the name describes what it does.

Fail. The character is text a user would say (a digit or a letter) and the name does not contain it, which fails WCAG 2.5.3.

View source