Symphonious

Living in a state of accord.

aria-labelledby vs aria-label

In ARIA, there are two ways that you can attach a label to an element, aria-label and aria-labelledby. In theory, you should use aria-labelledby if the text is visually on-screen somewhere and this form is preferable. You should only use aria-label when it’s not possible to have the label visible on screen. This makes a lot of sense because generally sighted users like to be able to see the label as well and it prevents the visual and non-visual cues from getting out of sync.

However, with current support, you should always use aria-labelledby, even if you need the label to be hidden. While at least JAWS 12 and VoiceOver both read the aria-label as expected, it turns out that VoiceOver doesn’t correctly read the hierarchy if aria-label is in use. For example:

<p id="group1">Outer group</p>
<p id="item1">First item</p>
<div role="group" aria-labelledby="group1">
<a href="javascript:" role="button" aria-labelledby="item1">Item Content</a>
</div>

everything here is using aria-labelledby and VoiceOver will read the button as “First item Outer group button”. In other words, the button label, the group label and then the type of object.

However, if you change any of the elements to use aria-label, for example:

<p id="item1">First item</p>
<div role="group" aria-label="Outer group">
<a href="javascript:" role="button" aria-labelledby="item1">Item Content</a>
</div>

VoiceOver will now read the button as simple “First item button”. It doesn’t seem to matter which item uses aria-label, if it’s anywhere in the hierarchy, only the label for the button itself will be read out.

Update

With JAWS on IE8 (and probably earlier versions) if you use aria-label instead of labelledby, it will read the text content of the item followed by the label (with no hierarchy), though intermittently it seems to omit the content. This creates a particularly bad experience if you’re labelled something like a DIV which has a lot of text content.