This is the first of a two parter about naming and labeling web content. These concepts can trip people up, and while there are other articles that have gone over these topics before, I haven’t. Or, at least, I have not explicitly. I’m sure I’ve said something about it before… hmm…

Anyway. There you have it. Or, is it “here” you have it?

I dunno, I wrote the intro to this as the last bit and I am tired now. This is definitely the worst part of the blog post. I’m not sorry. Please keep reading.

What’s an accessible name?

A “name” or “accessible name” for an element conveys its primary topic or purpose. Names are expected to be provided for interactive elements (e.g., links, form controls), and can be required (or, in some cases strongly recommended) for some non-interactive elements as well (form groupings, tables, dialogs).

There are certain elements that should not be named by developers. These include non-interactive text-level semantic elements, and other generic elements, such as <div>s. At best, naming generic elements like these work inconsistently and can create a disconnect with what’s visible on screen versus what is exposed to assistive technology.

For elements which can an need to be named, an accessible name should be as concise as possible, while still being descriptive to the element’s purpose. In some cases an accessible name could be a single word. In others, it can be as many words as needed to get the point across.

For instance, providing a <nav> an accessible name of “primary” will indicate that this navigation represents the primary navigation of a page.

We’ll come back to this topic in part 2.

What about a label?

A “label”, in accessibility-speak, does not always mean a <label>. Rather the term “label” is often used to refer to the “visible indicator” of an element, or even a grouping of elements. For instance, the following markup of a hyperlink (<a href>) would render with a visible label of “I’m some text!”

See the Pen A text link example by Scott (@scottohara) on CodePen.

But the following <button> has an icon as its visible identifier (i.e., “label”).

See the Pen A button with an pencil icon as it's visible 'label' by Scott (@scottohara) on CodePen.

In both of the above cases the “labels” of each interactive element provide their respective interactive parent elements’ their accessible names. “I’m some text!” for the link, and “Edit” (the text alternative provided for the <img> element), for the button.

Note: an image's text alternative is an image's accessible name. When an image with an accessible name is a child of a button, the button will get its name from the image's alternative text (and any other child content of the button, e.g., text that is a sibling to the image).

Labeling and naming elements with other elements

A <label> can also be used to “label” elements which can be labeled in HTML. When associating a <label> with a labelable element, it will be used to provide the accessible name for the element it is associated with.

<!-- not quite right -->
<label>Address</label>
<input>

In the above markup, while a <label> is used to “label” the <input> that follows, it is not associated with the form field, and thus does not provide it an accessible name.

Note: this markup example is a failure of multiple WCAG Success Criteria (1.3.1 Info an Relationships, 2.5.3 Label in Name, and 4.1.2 Name, Role, Value). But, by properly associating the <label> with the <input>, each of the failures will be rectified.

Associating a <label> with a form control can be done either by a direct programmatic association, or by nesting the <input> within the <label>. Either way the <label> will then provide the accessible name for the text field.

See the Pen Using a <label> to label and name an input by Scott (@scottohara) on CodePen.

While direct association (explicit labeling) with the for attribute, or nesting a form control within a <label> (implicit labeling) are both valid methods to name a form control with a <label>, there are support issues with Voice Dictation software. Keep this in mind when using <label> elements.

An aside on associating <label>s with form controls

By linking a <label> to a form control, mouse and touch users can also click/tap on the <label> and an action can occur.

In this particular example, clicking the <label> will send keyboard focus to the <input>. Allowing users to click/tap a <label> increases the overall target area of the <input>. This larger target area can help many users to more easily interact with the form control, and can benefit those who may have motor disabilities where larger target areas will help their ability to successfully click/tap the controls of a web page.

Not just <label>

The <label> element is not the only element which can both label and name certain HTML elements. For instance, the <legend> element can be used to provide a grouping of form controls a visible label, and an accessible name to that grouping.

See the Pen date range selection group by Scott (@scottohara) on CodePen.

In the above markup there are two <select> elements with the labels/accessible names of “Start” and “End”. They are preceded by a visible label of “Year range”. This text is provided within a <legend> element, which is the first child element of the <fieldset>. This specific markup pattern allows the <fieldset> to get its accessible name from the <legend> element. Someone using a screen reader to interact with these form controls will be be informed of the grouping name “Year range”, as well as the accessible name for each of the <select> elements (“Start” and “End”).

But where’s the ARIA?

Yes, ARIA attributes, specifically aria-label and aria-labelledby can be use to provide accessible names to various elements. That is, so long as the elements in question have an implicit or explicit ARIA role that is not “Name prohibited”.

As a quick comparison, <button aria-label=foo> would give the button a name of “foo”, but <div aria-label=foo> is something to be avoided.

Why? Well again, a <div> is a generic element, and naming generic elements makes no sense. Doing so has spotty “support” — where by “support” in this instance I rather mean “browsers and assistive technologies trying to mitigate developer misuse of the aria-label attribute”. <div> is supposed to be a container for content, it is not meant to convey any other semantics, let alone semantics important for accessibility. If you are going to name something with ARIA, it best be something that allows or needs naming. Otherwise, you’re either creating extra noise, or doing nonsense work that assistive technologies will ignore. No one likes doing nonsense work.

So don’t use ARIA? That’s the first rule, right?

Naming content with ARIA can be useful, when actually needed.

For instance, that edit button example from earlier, where the <button> was getting its name from a nested <img>. Let’s say, instead, there was no <img>. Rather, the edit icon is rendered via CSS as a background image, or a font icon. In such cases, we could use ARIA to name the button.

<button aria-label=Edit>
  <span class=edit-icon></span>
</button>

The <button> element will have the accessible name “Edit” from its aria-label. The <span> which renders the font icon can be ignored. An element with a button role (e.g., a <button>) is meant to treat its descendants as presentational. What that means is that even if we went to the trouble of updating the markup to be more like the previous example, with the native image, for instance…

<button>
  <span aria-label=Edit 
    class=edit-icon
    role=img
  ></span>
</button>

The above image role would be suppressed, because the button is supposed to be treating its descendants as presentational. So while the <button> would still get its name from the faux child “image”, the role of that image would be ignored… and thus it would be exposed no differently than the previous markup example where the aria-label was specified on the <button> element, itself.

Note: I say “supposed to” here because, due to many instances of invalid developer markup, sometimes important elements are nested inside of buttons. So, there very well could be instances / situations where buttons will expose the semantics of their child elements — but not always! And definitely not consistently across different browsers/AT pairings. Which, oh jeez, I’m staring into a rabbit hole full of disappointment.

Nope. That’s another post for some other time.

Anyway, aria-label can be used to name things, but it should be used only when necessary and when other native labeling mechanisms cannot be relied upon. Also, you’d do well to read up on how well aria-label behaves with translation services. aria-labelledby is definitely the preferred of the two attributes, not only for potential translation woes, but also the ARIA specification even points out that use of aria-labelledby is preferred over aria-label, particularly in cases where the content that will provide the element’s “label” is visually available.

For instance,

<!-- do not do this -->
<span>
  Address
</span>
<input aria-label=Address>

<!-- instead -->
<span id=n>
  Address
</span>
<input aria-labelledby=n>

<!-- but really, do this... you can just do this... -->
<label for=n>
  Address
</label>
<input id=n>

While all three of the above markup snippets will ensure that the text field has an accessible name of “Address”, the preferred option will always be the one using the <label> element.

Why?

  • Aside from the translation service issue mentioned before, having a separate text string for the visible label and the aria-label of the form control introduces the possibility that these could become out of alignment. “Oh, Scott” you say, “surely one would just make sure the same text string populated both the contents of the <span> and the aria-label of the <input>!” Yeah, yeah. You would think that. And most of the time you’d be right. But hey, guess what. People mess up sometimes. And then, they don’t always double check their code, particularly not with a screen reader. So, you get those weird instances where visually things look a-OK, but under the hood the accessible name of the “Address” field is some other random string of nonsense. Maybe, even a broken ng-whateverTheHell JSON object.
  • So why not aria-labelledby then? Well, it is the better choice of those two. But a properly associated <label> allows a user to also click or tap on that <label> and (at minimum - depending on the type of associated form control) automatically send keyboard focus to the form control in question. A static text string associated with a form control via aria-labelledby does not provide this functionality by default, which is also quite helpful for people with motor disabilities who would benefit from larger hit targets for controls. If you want to add that functionality, you’re looking at needing to write it yourself. And that’s work. Why do you want to do extra work?

Wrapping up part one

I think this is a good place to pause and reflect on what was outlined in this post.

Elements, particularly interactive elements, need names. These names inform users of assistive technologies of the element’s purpose. A name can be derived from an element’s label — which may be its visible identifier (text or an image, for instance). That label can be nested within some elements, like a link or a button, or it can be associated with the element via a <label> or <legend> element, depending on what the element that needs to be named supports.

Additionally, aria-label and aria-labelledby can also be used to provide accessible names to elements, so long as those elements allow for naming via these attributes. These attributes, though, should be used when other native HTML features cannot be used.

There are additional mechanisms for naming content that I did not cover in this post. For instance, the title attribute can be used to name many HTML elements. However, the title attribute has a whole bunch of baggage to it. I’ve written about the title attribute before, as have many others. Also, the naming of <table> or <figure> elements was not covered in this post.

Why?

Because I didn’t want to write about those today. There’s enough here for now to get along with… and there’s going to be a part 2 to this post. So, be excited! Or, at least patient?

I dunno. I need to go write the intro to this now.

Further reading

As mentioned, others have discussed these sorts of topics before. You can probably spoil my next blog post by reading these: