My Priority of Methods for Labeling a Control

Here is the priority I follow when assigning an accessible name to a control:

  1. Native HTML techniques,
  2. aria-labelledby pointing at existing visible text,
  3. Visibly-hidden content that is still in the page,
  4. aria-label.

Too often folks will grab ARIA first to provide an accessible name for a thing. Or they may sprinkle hidden content around a form. Sometimes this is to satisfy a (minimalist?) design, other times it is just part of the tooling. In most cases the impact of those decisions is unknown. The assumption that they do the same thing, give the same output to all users, is wrong.

The priority I follow is intended to honor ARIA best practices and internationalization concerns. I also gathered feedback on the Twitters (which is just anecdata).

This does not talk about hint text (such as something defined by aria-describedby), also known as an accessible description.

Native HTML

This includes using a <label> for form elements, or the value attribute (for <input type="submit">) or inner text (for <button>).

It is well-understood by browsers, with more than two decades of support. It provides a larger hit area when tapping or clicking an associated field. Screen readers understand the pairing. Voice recognition tools understand it for selecting fields.

Well, one caveat on that last one. Dragon does not like fields wrapped in <label>. If you are old-school you probably remember when Internet Explorer did not like it either. So do this:

<label for="Name">Name:</label>
<input type="text" id="Name">

Instead of this:

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

Content in <label> also gets picked up by all translation services (Google, Bing, some older ones whose names I have forgotten but used years ago). If you have reason to build screens with mixed language, <label>, <input type="submit">, <button>, and other controls will happily take a lang attribute.

aria-labelledby with Visible Text

This relies on ARIA, but by associating visible text on the page all users can at least access it. aria-labelledby works as the selectable name for voice control tools (on Windows, I am still testing on iOS and macOS). aria-labelledby can be translated and the container of the referenced text can (almost definitely) take the lang attribute in the case of mixed language content.

aria-labelledby will accept a space-separated list of id references, meaning you can build a more robust accessible name from disparate pieces of text in the page, including the control itself. I demonstrate this technique in my post Uniquely Labeling Fields in a Table and paste a couple code samples here:

<td>
  <input type="text" id="c01" aria-labelledby="Row01 ColClaimed">
</td>
<td>
  <button type="button" id="b01" aria-labelledby="b01 Row01">Remove</button>
</td>

It does not increase the hit area of a control when used as its visible label. Some older screen reader and browser pairings (much older) that pre-date broad support for aria-labelledby will struggle.

Perhaps the biggest risk here is that aria-labelledby overrides all the other methods for providing an accessible name. This sometimes surprises developers who throw it on a control, overriding an associated <label>.

Visibly Hidden Content

This is generally achieved by taking plain text on the page and hiding it off-screen somehow. Often this is done with text that is already associated with a control, such as a <label>, content referenced by aria-labelledby, or the inner text of a <button> or link (think icon fonts). You may see this in the wild with a sr-only or visually-hidden class.

In cases where CSS is used to provide icons or other information (via ::after or background images), when the CSS breaks this information may be lost. The hidden text would also become visible (if the hiding technique is in the same CSS resource), making this a viable approach when supporting progressive enhancement.

This content will still be translated and can still accept a lang attribute (by putting it on the container hiding it).

The only users who will know it is there are screen reader users, however. It is not visible. It does not help the click/tap size of the control. It is not available to voice users to select a control. It cannot be copied.

Hidden text is also used too casually to provide information for just screen reader users, creating overly-verbose content. For sighted screen reader users, it can be a frustrating experience to not be able to find what the screen reader is speaking, potentially causing the user to get lost on the page while visually hunting for it.

If the wrong technique is used to hide content it can have additional problems. Content hidden solely by positioning it outside the viewport (left:-9999px) can create confusing scrollbars or come into view if the page is translated. Content confined to a tiny box can be spoken letter by letter if not addressed. The styles you use must take these issues into account.

The CSS I use:

/* Method to visually hide something but still */
/* make it available to screen readers */
.visually-hidden {
  position: absolute;
  top: auto;
  overflow: hidden;
  clip: rect(1px 1px 1px 1px); /* IE 6/7 */
  clip: rect(1px, 1px, 1px, 1px);
  width: 1px;
  height: 1px;
  white-space: nowrap;
}

I encourage you to read Scott O’Hara’s post Inclusively Hidden.

aria-label

aria-label overrides other methods for providing an accessible name, except aria-labelledby. Since the text is not visible a developer can forget it is there, overriding an associated <label>, making it potentially riskier than aria-labelledby‘s override.

aria-label is a challenge for internationalization. You cannot count on content in aria-label to be auto-translated (and in my experience is often missed in manual translation). It definitely cannot take a lang attribute on its own, meaning you have to put lang on the control itself, which may or may not be what you want.

The only users who will know it is there are screen reader users. It is not visible. It does not help the click/tap size of the control. It is not available to voice users to select a control. It cannot be copied.

It can also too easily be used to create overly-verbose content. It can be confusing in the wrong context for sighted screen reader users.

Sometimes aria-label is misunderstood to the point that it is used for hints, without understanding it will confuse screen reader users and strand voice users, ie:

Only those with <a href="[…]" aria-label="Learn more about permission levels">write access</a> to this repository can merge pull requests.

Similarly, avoid constructs / copy-paste errors like the following:

<label for="foo">First Name:</label>
<input type="text" id="foo" aria-label="Address Line 2">

Unlike visibly hidden content, aria-label will not become visible when the CSS or script for the page fails to load (this is neither good nor bad, but worth remembering).

Exceptions

Yes, there are exceptions.

I am talking about interactive controls, though some of these rules apply to non-interactive controls (such as landmarks or <iframes>). The ARIA approaches won’t work for other elements (this is a good thing) unless they have an appropriate role applied (this is generally only a good thing for complex widgets).

You may also have restrictive business cases (change them?), build processes (rebuild them?), or technologies (replace them?) that give you little control over what options are used in various contexts.

Conversely, you may have run tests with your own users (yay!) that demonstrate one approach is better than another. Use that one. Just be careful about extrapolating out to all cases.

This post does not mean I am right. I am, however, happy to be proven wrong or shown other cases. Other readers of this post may benefit from your comments.

No comments? Be the first!

Leave a Comment or Response

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.