konstantin konstantin - 3 months ago 10
HTML Question

When do I have to use ARIA attributes and landmarks?

Is there a simple rule when I have to add ARIA attributes and landmarks?

For example do I need the

aria-checked
for an input type checkbox or radio? Or do I need to add an
role="main"
to the
<main>
element? Do I have to add a
role="navigation"
to a
<nav>
element?

Is there a list where I can look which ARIA landmarks and attributes I have to add?

Answer

Is there a simple rule when I have to add them?

Yes, any time the implicit semantics for an element do not match your usage you should add appropriate [role] attributes to make the non-standard usage be known to the browser.

By "semantics"—a word that means "meaning"—I'm referring to the browser's ability to automatically interpret elements based on their definition in the HTML spec (or the other HTML spec).


This is easier to see with an example.

Suppose you have a design that has a button. A typical way to mark up this UI is by using the <button> element and a click handler (jQuery used for brevity):

HTML:
<button type="button" class="start">Start</button>
JS:
$('.start').click(start);

However, sometimes due to exceptional circumstances there are cases where <button> is either inappropriate or invalid, such as when you must put a <div> within the button. In these cases it is typical to see a <div> used:

HTML*:
<div class="start">
    <div>...stuff...</div>
</div>
JS*:
$('.start').click(start);

*This is a naive example, don't do it this way

The problem with this approach is that the browser doesn't know that the <div class="start"> element is a button and should be treated as a button. This means that the browser won't tell assisted navigation such as a screen reader that the element should be identified as a button. It also means the browser doesn't know that it should be in the tabbing order for keyboard-only users, and that it needs to be focusable, and trigger click events with Enter or Space key events.

Once you choose not to use the native semantic elements, you have to do additional work to support native behavior.

To tell the browser to identify the element as a button, you'd use [role="button"]:

<div role="button" class="start">

To tell the browser to include the element in the tabbing order, you'd give it a [tabindex] attribute:

<div role="button" tabindex="0" class="start">

To tell the browser to trigger click events on Enter or Space, you'd need to handle those behaviors via JavaScript:

$('.start').keydown(function (e) {
    switch (e.which) {
    case 13: //ENTER
    case 32: //SPACE
        $(this).click();
        break;
    }
});

This means to make a <div> into a proper <button> the example would be:

HTML:
<div role="button" tabindex="0" class="start">
    <div>...stuff...</div>
</div>
JS:
$('.start').keydown(function (e) {
    switch (e.which) {
    case 13: //ENTER
    case 32: //SPACE
        $(this).click();
        break;
    }
}).click(start);

It's easy to forget to do all of those things, it's much simpler to just use <button type="button"> and take what the browser gives you for free.

Sometimes though, there are no native elements available for the interface you're creating.

The WAI Aria spec has a nice list of all the roles that are available.

Many of these roles don't have a native equivalent. A simple example is of a tabbed interface. Historically tabbed interfaces have been marked up along the lines of:

<div class="tabs">
    <a href="#panel-1" class="tab">Foo</a>
    <a href="#panel-2" class="tab">Bar</a>
    <a href="#panel-3" class="tab">Baz</a>
</div>
<div class="panels">
    <div class="panel" id="panel-1">
        Lorem ipsum tab panel 1
    </div>
    <div class="panel" id="panel-2">
        Lorem ipsum tab panel 2
    </div>
    <div class="panel" id="panel-3">
        Lorem ipsum tab panel 3
    </div>
</div>

But to a blind user this would be read as a list of links and then a small amount of content. To fix this so that the <a> elements are identified as tabs instead of links the [role] attribute is used. There are additional roles for other parts of the tab interface, as well as some [aria-*] attributes that assist the browser in identifying the current state of the UI:

<div role="tablist" class="tabs">
    <a role="tab" aria-selected="true" aria-controls="panel-1" href="#panel-1" class="tab">Foo</a>
    <a role="tab" aria-selected="false" aria-controls="panel-2" href="#panel-2" class="tab">Bar</a>
    <a role="tab" aria-selected="false" aria-controls="panel-3" href="#panel-3" class="tab">Baz</a>
</div>
<div class="panels">
    <div role="tabpanel" aria-expanded="true" class="panel" id="panel-1">
        Lorem ipsum tab panel 1
    </div>
    <div role="tabpanel" aria-expanded="false" class="panel" id="panel-2">
        Lorem ipsum tab panel 2
    </div>
    <div role="tabpanel" aria-expanded="false" class="panel" id="panel-3">
        Lorem ipsum tab panel 3
    </div>
</div>

All of this additional information might seem tedious to add, but it is vital to ensuring that the browser can correctly identify the content that is being rendered to the user and provide the appropriate assistance to users who need it.


Is there a list where I can look which ARIA landmarks and attributes I have to add?

The w3c WAI ARIA spec has details on how each role should be used and what attributes are appropriate to use alongside those roles. There are also numerous questions on Stack Overflow about how to mark up specific UI patterns to be accessible, but be aware that the quality of answers will often be spotty because there are few accessibility experts that have truly tested their "accessible" markup.

When in doubt, consult an expert, and perform user tests to verify that the solutions in use meet your criteria for success.

Comments