Updated June 10th 2024
Like aria-label
, aria-labelledby
provides the opportunity for a developer to expose a short text string as the accessible name for an element. The mechanism to do so differs. While aria-label
accepts a string of text, aria-labelledby
accepts 1 or more id
values (NOT a STRING OF TEXT).
The same opportunity is afforded by native HTML labelling features, please do use the native features wherever practical!, for example:
<label for="pithy">poot</label> <input type="text" id="pithy">
<img alt="creamy pie">
<button>belt on</button>
aria-labelledby
is one of a number of secondary methods to label native HTML UI elements. It works particularly well on interactive elements, it also works well on most block level elements old skool term that have explicitly or implicitly defined structural roles. It works less well or not at all on text level semantics. It is prohibited as are any form of accessible name on a whole slew of roles.
Implicit roles are those applied automatically by browsers to native HTML elements.
Explicit roles are those applied by developers using the role
attribute. When applied they override the implicit role of an element.
(Somewhat out of place here) general rules for labeling
- Prefer visible over hidden labels
- Prefer text labels over icons
- If icons are used provide a supplementary text label ( may be displayed on focus/hover)
- Place visible labels as expected:
- For a checkbox or radio button, place the label immediately after the field.
- If not a checkbox or radio button, place the label immediately before the field.
- Prefer native HTML labeling mechanisms, for Native HTML controls, over ARIA labeling mechanisms.
Never be tempted to use placeholder text as a label. It SUX.
Questions on aria-labelledby usage
I find myself regularly asking the these questions in regards to aria-label
:
- Is it a good idea to use
aria-labelledby
on element X? - Does
aria-labelledby
work as expected i.e is announced by screen readers on element Z? - Is
aria-labelledby
allowed on element Y?
FYI empty aria-labelledby=""
does not equal empty alt=""
, the latter signals that an img
element has no useful information, the former does nothing.
aria-labelledby
masks any other accessible name source.
aria-labelledby
referencing content
hidden content
It’s legit for aria-labelledby
to reference a hidden element, it makes no difference to the resulting accessible name if the content is hidden (using CSS display:none
, for example) Refer to Hiding Content Has No Effect on Accessible Name or Description Calculation
<a href="beefy.html" aria-labelledby="unseen">now you don't</a> <p id="unseen" hidden>Now you hear me</p> accessible name: "Now you hear me"
self and multiple references
You can include text that would be exposed as the accessible name if aria-labelledby
wasn’t there by adding an id
to the element with the aria-labelledby
and referencing the value, you can also reference multiple elements:
<a href="noise.html" id="heard" aria-labelledby="unseen heard"> now you do</a> <p id="unseen" hidden>Now you hear me,</p> accessible name: "Now you hear me, now you do"
The order in which you reference the id
values effects the string concatenation order:
<a href="alphabet.html" id="pre" aria-labelledby="pre a b c">Easy as</a> accessible name: "Easy as A B C" <a href="alphabet.html" id="pre" aria-labelledby="pre c b a">Easy as</a> accessible name: "Easy as C B A" <span id="a">A</span> <span id="b">B</span> <span id="c">C</span>
Spaces between strings are added by the browser
Today I learned that concatenated text does now have spaces by default, mea culpa.
Append the
result
of each step above, with a space, to thetotal accumulated text
.
source: https://w3c.github.io/accname/#computation-steps
Be aware that concatenated text does not have spaces by default, so you will need to include spaces.
<a href="alphabet.html" id="pre2" aria-labelledby="pre2 a b c">Easy as</a> accessible name: "Easy asABC" <a href="alphabet.html" id="pre2" aria-labelledby="pre2 a b c">Easy as </a> accessible name: "Easy as ABC" <span id="a">A</span> <span id="b">B</span> <span id="c">C</span>
Try it yourself – Codepen aria-labelledby examples
See the Pen
aria-labelledby examples by steve faulkner (@stevef)
on CodePen.
humble guidance
For HTML elements I have provided some guidance on aria-labelledby
usage (which by all means you may disagree with):
HTML element | aria-labelledby | notes |
---|---|---|
a with href |
yes | Masks text content, so only aria-labelledby is announced:
Be wary of label in name issues |
a without href |
no | a without href is not a link and not exposed as a link . Maps to role=generic naming not allowed |
abbr |
no | title attribute works but announcement is a user preference in some screen readers (off by default). Refer to Short note: The abbreviation appreciation society |
address |
no | Does not mask content: accessible name provided via aria-labelledby should generally be announced when the address is navigated to.
|
area with href |
no | use alt |
area without href |
no | a without href is not a link and not exposed as a link . Maps to role=generic naming not allowed |
article |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the article is navigated to. |
aside |
yes | Does not mask content. Accessible name provided via aria-labelledby will generally be announced when the aside is navigated to. |
audio |
yes | Prefer visible, a heading perhaps (via aria-labelledby if you like) |
b |
no | Maps to role=generic naming not allowed |
base |
no | not UI |
bdi |
no | Maps to role=generic naming not allowed |
bdo |
no | Maps to role=generic naming not allowed |
blockquote |
no | aria-labelledby use not well supported |
body |
no | aria-labelledby use not supported |
br |
no | Maps to role=generic naming not allowed |
button |
yes | masks text content, so only aria-labelledby is announced:
Be wary of label in name issues |
canvas |
no | Use child content
|
caption |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
cite |
no | Maps to role=generic naming not allowed |
code |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
col |
no | not UI |
colgroup |
no | not UI |
data |
no | Maps to role=generic naming not allowed |
datalist |
no | For aria-labelledby on <datalist> element itself. |
dd |
no | aria-labelledby use not well supported |
del |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
dfn |
no | aria-labelledby use not well supported |
details |
yes | Does not mask content: When details has an accessible name it is announced as a group along with its accessible name (test case). |
dialog |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the dialog is navigated to. |
div |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
dl |
yes | Fairly good support across browsers/screenreaders. |
dt |
no | aria-labelledby use not well supported |
em |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
embed |
no | aria-labelledby use not well supported |
fieldset |
yes | aria-labelledby overrides accessible name from legend content (if present). Otherwise, does not mask content: accessible name provided via aria-labelledby will generally be announced when the fieldset is navigated to. |
figcaption |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
figure |
yes | aria-labelledby overrides accessible name from figcaption content (if present). Otherwise, does not mask content: accessible name provided via aria-labelledby will generally be announced when the figure is navigated to. |
footer |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the footer is navigated to. |
form |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the form is navigated to. |
form-associated custom element | yes | Unless the custom element is an extension of a native HTML interactive element, ARIA labeling (aria-label , aria-labelledby ) is the primary method of labeling. |
h1 to h6 |
no | aria-labelledby use not well supported, works with NVDA/VoiceOver not with JAWS
Masks text content, so only
|
head |
no | not UI |
header |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the header is navigated to. |
hgroup |
no | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the hgroup is navigated to.
|
hr |
yes | Will generally be announced when the hr is navigated to. |
html |
no | not UI |
i |
no | Maps to role=generic naming not allowed |
iframe |
yes | Use title attribute for accessible name |
img with alt ="some text" |
no | Use alt attribute for accessible name |
img with alt ="" |
no | use alt |
img without alt attribute |
no | if you want to add an accessible name to an <img> use alt attribute for accessible name |
input type=button |
yes | accessible name from value preferred |
input type=checkbox |
yes | accessible name from label preferred |
input type=color |
yes | accessible name from label preferred |
input type=date |
yes | accessible name from label preferred |
input type=datetime-local |
yes | accessible name from label preferred |
input type=email |
yes | accessible name from label preferred |
input type=file |
yes | accessible name from label preferred |
input type=image |
no | if you want to add an accessible name to an <input type=image> use alt |
input type=month |
yes | accessible name from label preferred |
input type=number |
yes | accessible name from label preferred |
input type=password |
yes | accessible name from label preferred |
input type=radio |
yes | accessible name from label preferred |
input type=range |
yes | accessible name from value preferred |
input type=reset |
yes | accessible name from value preferred |
input type=search |
yes | accessible name from label preferred |
input type=submit |
yes | accessible name from value preferred |
input type=tel |
yes | accessible name from label preferred |
input type=text |
yes | accessible name from label preferred |
input type=time |
yes | accessible name from label preferred |
input type=url |
yes | accessible name from label preferred |
input type=week |
yes | accessible name from label preferred |
ins |
no | Maps to role=generic naming not allowed |
kbd |
no | Maps to role=generic naming not allowed |
label |
no | Maps to role=generic naming not allowed (until ARIA 1.3) |
legend |
no | aria-labelledby use not well supported |
li |
no | aria-labelledby use not well supported |
link element with ahref |
no | Don’t use link in body |
main |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the main is navigated to. |
map |
no | not UI |
math |
no | The math element is not currently supported in modern browsers. |
mark |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
menu |
no | This element sucks in general, suggest not using. |
meta |
no | not UI |
meter |
yes | accessible name from label preferred |
nav |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the nav is navigated to. |
noscript |
no | not UI |
object |
no | aria-labelledby use not well supported |
ol |
yes | Fairly good support across browsers/screenreaders. |
optgroup |
no | Use label attribute |
option |
no | Use text content of option or use a label attribute. |
output |
no | aria-labelledby use not supported |
p |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
param |
no | not UI |
picture |
no | not UI |
pre |
no | Maps to role=generic naming not allowed |
progress |
yes | accessible name from label preferred or a heading perhaps (via aria-labelledby if you like). |
q |
no | Maps to role=generic naming not allowed |
rp |
no | Maps to role=generic naming not allowed |
rt |
no | Maps to role=generic naming not allowed |
ruby |
no | Maps to role=generic naming not allowed |
s |
no | Maps to role=generic naming not allowed |
samp |
no | Maps to role=generic naming not allowed |
script |
no | not UI |
search |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the search element is navigated to. |
section |
yes | Does not mask content: accessible name provided via aria-labelledby will generally be announced when the section is navigated to. |
select |
yes | accessible name from label preferred |
slot |
no | not UI |
small |
no | Maps to role=generic naming not allowed |
source |
no | not UI |
span |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
strong |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
style |
no | not UI |
SVG |
yes | alt="some text" DOES NOT WORK even if the SVG (or any other element) has a role="img" |
sub |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
summary |
no | aria-labelledby use not well supported |
sup |
no | refer to Roles which cannot be named (Name prohibited) ARIA 1.2 |
table |
yes | Prefer visible caption element text |
tbody |
no | aria-labelledby use not well supported |
template |
no | not UI |
textarea |
yes | accessible name from label preferred |
tfoot |
no | aria-labelledby use not well supported |
thead |
no | aria-labelledby use not well supported |
time |
no | Maps to role=generic naming not allowed |
title |
no | aria-labelledby use not supported |
td |
no | aria-labelledby use not well supported |
th |
no | aria-labelledby use not well supported |
tr |
no | aria-labelledby use not well supported |
track |
no | not UI |
u |
no | Maps to role=generic naming not allowed |
ul |
yes | Fairly good support across browsers/screenreaders. |
var |
no | Maps to role=generic naming not allowed |
video |
yes | Prefer visible, a heading perhaps (via aria-labelledby if you like) |
wbr |
no | Maps to role=generic naming not allowed |
5 replies on “aria-labelledby usage notes”
Nice article! With surprises worth mentioning:
Controls sometimes don’t get a reliable name from their SVG content.
Naming changes the role of
section
andform
elements.thanks Mitchell!
I find myself regularly asking the these questions in regards to aria-label: <- should that be aria-labelledby?
Should second column in Humble guidance table also be aria-labelledby?
Hey Mark, yep it should, updated!