Practical accessibility, part 2: Name (almost) everything

When browsers and screen readers encounter an element, they use semantic markup and ARIA attributes to tell users what it is (ul is a list) and how it’s supposed to work (role="menu"). But they can’t say why it’s there without an accessible name.

Accessible names can be summed up as: the text that identifies this instance of an element or component. It’s the text in a link or button, a heading element associated with a widget, or a form element’s label. It’s the value given to attributes like aria-labelledby and aria-label when visible labels would get in the way (think: global navigation bar).

It seems like a simple concept, but like many things in web development, naming is both critical to accessibility and very easy to omit or implement badly.

Why it matters to get naming right

Aside from the fact that names are required to achieve the most basic level of accessibility compliance, they provide wayfinding assistance, differentiate similar widgets from each other, and inform users of assistive technology how your interface works.

Elements and components on your page that are interactive or contain meaningful content need identifying text in the markup. Screen readers rely on text to create a usable experience. Voice control users need clear text labels that match the underlying code so they can accurately move about the page.

But this doesn’t mean we should slap a name on everything. It requires some restraint. Too many names, or names applied incorrectly, and you could end up with noisy or unusable content.

Which elements need explictly set names?

Essentially, the following:

  • focusable, interactive elements - links, forms and form elements, custom-built widgets like accordion, carousel, tabs, etc
  • non-text elements that require a text equivalent - images, icons, videos, embedded frames
  • labeling elements - headings, form labels
  • tables, too, via the caption element

Some elements should remain anonymous

Generally, elements that don’t gain focus, convey meaningful content, or enable user interaction can safely remain nameless and in the background. This is true of non-specific elements that lay out the page, like <div class="column">, or elements that are purely decorative. In fact, naming everything to that degree could be distracting to screen readers who are listening for salient content.

Do landmarks need names? Yes and no.

Landmarks identify major sections of the page for screen readers and can be accessed via screen reader-specific key commands — whether their content is interactive or not. (For a refresher on landmark semantics and roles, see Part 1.)

A name is required for some landmarks, but not for others. Landmarks that are limited to one per page, like a top-level banner, can be identified by their role alone.

I made up cheat lists to sort them out, and noted role values that confer landmark status (i.e., navigation) and sectioning elements that have implied landmark roles (<nav>):

Landmarks that require a name

  • navigation or <nav>, especially when multiple exist on a page
  • form or <form> - not just a name, but a visible name
  • region, which by definition is unspecific so it needs a name to clarify its purpose
  • main or <main> - not technically required, but I’ve included it here because it’s good practice to associate the H1 element with the main content in your page via aria-labelledby

Landmarks that may be named

Names are not required for accessibility compliance, but may provide additional context.

  • complementary or <aside>
  • search
  • <section> when you want it to act as a region landmark. Out of the box this element is not considered a landmark unless it’s assigned aria-label, aria-labelledby, or title.

Landmarks that shouldn’t be named

Adding names to these could be distracting to screen readers. Instead, let their roles and content do the work.

  • banner, or <header> when it’s a direct child of <body> (has implied banner role)
  • contentinfo or <footer> when either is a direct child of <body>
  • application conveys information about the interface but is not exposed to screen reader users for navigation

Ways to name things

Accessible names are applied in several ways: with a text value (links, buttons), form label, text associated with aria-labelledby, or an aria-label attribute. An important bit to remember is that screen readers follow a fairly strict order of precedence:

  1. aria-labelledby - if this exists, no other naming attribute or text value will be read; it even overrides label elements associated with form controls.
  2. aria-label - in the absence of aria-labelledby, this acts the same way, it takes precedence over other naming attributes and text.
  3. When no ARIA labels are present, label elements and other attributes, like title, or text in the markup are read.

Some words of caution when using ARIA for labeling

ARIA labeling attributes illustrate why “no ARIA is better than bad ARIA” — they can override an element’s text value. Always test how they sound in a screen reader to ensure they accurately identify the element and match any related text/imagery that is visually displayed (that’s the gist of WCAG’s success criterion 2.5.3, label in name).

Note: Google Developers’ ARIA Labels and Relationships provides a clear and concise breakdown of how labeling attributes relate to each other.

How I name things

All of this can be a lot to remember, so I use a process of elimination to determine which naming method or attribute to apply per element/component.

1. Does it have a “built-in” way to assign an accessible name?

Many HTML elements come with features and attributes for naming. Before considering ARIA attributes, assign names with:

  • visible button or link text
  • a <label> element properly associated with its form control
  • alt attributes on images
  • table <caption> elements

2. If there’s no naming feature or attribute, use ARIA

When using ARIA labelling attributes, test the rendered code in a screen reader to ensure they’re read as intended.

2a. Can a visible label be displayed?

Use aria-labelledby to relate an element or component to a heading element:

<h3 id="subjects-heading">Classes by Subject</h3>
<div class="accordion" aria-labelledby="subjects-heading">
...
</div>

In this example, any focusable content within the Classes by Subject accordion will be identified as belonging to that group. It’s very similar to when you focus on an input that’s properly associated with a label.

Before we move on, I want to reiterate that visual labels are beneficial to all users, regardless of ability. They:

  • allow for a quick scan of the page to understand content priority or required steps
  • help screen reader users follow along with page content
  • provide labels for voice control users
  • when coded with proper semantics, act as pseudo navigation for assistive tech (screen reader and voice control users can jump to headings and form controls)
  • maintain context when a page is zoomed (WCAG 2.0 compliance requires that a user be able to zoom their viewport up to 200% “without loss of content or functionality”)

2b. When a visible label doesn’t work

Sometimes a visible label would be redundant or won’t fit in the space alotted on a small screen, so a name just for screen readers will suffice. Use aria-label directly on the component’s opening tag for:

  • icons that convey meaning (not purely decorative)
  • icon buttons
  • any interactive component, especially when multiples exist (menus, tabs, accordions, carousels, etc)
<button aria-label="Print recipe"><span class="icon-print"></span></button>

What to name things is equally important

A good name should be brief (avoid extras like “a" or “the" unless it’s a proper noun) and not repeat the role or widget type (screen readers will include the role/element in their read out by default, i.e., VoiceOver says “Print recipe, button”).

Recommended (visible label):

<h3 id="headingID">Development resources</h3>
<div role="tablist" aria-labelledby="headingID">

Also good, when a visible label doesn’t work:

<div role="tablist" aria-label="Development resources">

Don’t do this:

<div role="tablist" aria-label="tabs">

Check your names

You can verify a widget’s accessible name and how it’s derived (text value vs ARIA attribute, for example) in the browser’s code inspector. Both Chrome and Firefox dev tools include an Accessibility panel that displays the accessibility tree and each element’s attributes:

Firefox browser inspector panel displaying the accessibility tree.

There’s more to a name

There are complexities to naming and labeling elements that I haven’t covered here for the sake of brevity. I found these articles particularly useful (and engaging), and recommend them for further reading:

  • I found Joe Watkins’ Demystifying Accessible Name helpful in understanding names as they relate to the Accessibility API/tree. He also includes many concrete code examples.
  • Sarah Higley’s take, What’s in a name?, should be required reading for understanding the many nuances of applying accessible names across widget types, and she covers the topic in enormously helpful detail. (Her blog is a fantastic resource for accessible coding practices in general.)
  • If you’re also a specification nerd, you may enjoy working your way through the W3C’s Accessible Name and Description Computation 1.1 to better understand the recommendation for how names are gleaned from the code.

Let us know what you think!

All blog posts