Each accessible object may have name and description, a primary characteristic used for perceivability of the control element by the user (also referred as text equivalent). As far as I know only ARIA spec provides an algorithm of text equivalent computation. It might look strange that ARIA specifies an universal algorithm equally applicable to any markup (would it be HTML or anything else) but that's how it is. Other specs either don't address that or like HTML spec are referred to the ARIA one. Each browser follows that algorithm this or that way.
Algorithm implemented in Firefox isn't 1 to 1 with ARIA's one but it is quite close to the version from ARIA first draft. Basically that version was written from Firefox implementation. ARIA was evaluated, Firefox was evaluated too but not always in sync with ARIA.
I realized that Firefox algorithm isn't documented anywhere so I decided to put it here to not make people read the code if they are curious about Firefox behavior. Note, Firefox might do a slightly different computations on case by case basis. In general these should considered as bugs. However this algorithm is not free from bugs as well. Let me know if you see anything suspicious.
Here is a list of used terms in algorithm description:
To compute the text equivalent for
Text equivalent computation from ARIA and native markup is nicely covered by HTML to a11y spec.
Nevertheless as example of a native markup text equivalent can be alt attribute for HTML <img> or a label from <label for> for control element. However, markup for tooltips is not used as native markup text equivalent, they are used as a last resort under item f.
In general name and description don't dupe each other so that if some markup was used as name then it won't be reused as description. For example,
<img title="Me and Eiffel Tower">
Name is "Me and Eiffel Tower", description is empty.
But:
<img alt="I'm in France" title="Me and Eiffel Tower">
Name is "I'm in France", description is "Me and Eiffel Tower".
Example of
Example of
<button aria-labelledby="span" id="btn" />
<button aria-labelledby="btn" id="btn2" />
<span id="span">text</span>
@id="btn" name is "text",
@id="btn2" doesn't have a name,
Note, if the recursion only produces white space then we proceed to the next item of the algorithm. For example
<span id="span"></span>
<button aria-labelledby="span">press me</button>
Name of button element is "press me". The rule is also applicable to item e.
1. By user-managed value we assume the
2. If the
<div role="slider" aria-valuetext="right in the middle"></div>
Name is empty for ARIA slider.
3. But if the
<label for="input">
Position
<div role="slider" aria-valuetext="right in the middle">
</div>
</label>
<input id="input" type="checkbox">
Name of the checkbox is "Position right in the middle".
4. If the
a. If the node is in middle of text equivalent computation then its value is included.
<label>
Subscribe to
<select>
<option>ATOM</option>
<option>RSS</option>
</select>
feed.
</label>
Name for select is "Subscribe to ATOM feed".
b. If node is not in the middle of text equivalent computation then value is omitted.
<label>Home page: <input type="text"></label>
Name for input is "Home page:".
Algorithm implemented in Firefox isn't 1 to 1 with ARIA's one but it is quite close to the version from ARIA first draft. Basically that version was written from Firefox implementation. ARIA was evaluated, Firefox was evaluated too but not always in sync with ARIA.
I realized that Firefox algorithm isn't documented anywhere so I decided to put it here to not make people read the code if they are curious about Firefox behavior. Note, Firefox might do a slightly different computations on case by case basis. In general these should considered as bugs. However this algorithm is not free from bugs as well. Let me know if you see anything suspicious.
Terms
Here is a list of used terms in algorithm description:
initial node
- the DOM node the text equivalent is computed for;
current node
- the DOM node currently traversed in order to compute the text equivalent for
initial node;
text equivalent string
- the text equivalent we have computed up until we have arrived at the
current node;
string attribute
- attribute whose value provides a text equivalent, for example,
aria-label
in case of name computation; relation attribute
- IDRefs attribute referred to other element(s) used in text equivalent computation, for example,
aria-labelledby
in case of name computation; empty on purpose text equivalent
- text equivalent left empty on purpose by the author, AT shouldn't try to repair it.
Algorithm
To compute the text equivalent for
current node
:- Prepend a space if necessary: if the
current node
is not inline element (refer to CSS display style), append a space character if thetext equivalent string
is not empty. - Compute the text equivalent for the
current node
and append it totext equivalent string
:-
If the node is hidden and it's not a part of computation initiated by
relation attribute
(in other words, it's not referred by or it's not a child of hidden element referred byrelation attribute
) then, skip the node. ⤴ - If the node is a text node, then append the rendered text content if the node is not hidden, otherwise its append text content. Proceed to the next node. ⤴
- Append text equivalent from ARIA markup if any, otherwise append it from native markup:
- If text equivalent is provided by
string attribute
then append its value. Ifstring attribute
value is empty and the text equivalent won't be provided later by the algorithm then text equivalent is consideredempty on purpose
. - If text equivalent is provided by
relation attribute
, and this node is not already part of text equivalent calculation, then within therelation attribute
value, process the IDs in the order they occur and ignore IDs in that are not specified on an element in the document. For each ID's associated element, implement this text equivalent computation starting with step 1, appending the results to thetext equivalent string
as they are collected.⟲ -
If the node is not
initial node
or if it's recursively reenteredinitial node
but it's not the fist or last part of a text equivalent computation then append the current user-managed value of this node.
-
If the text equivalent for this node is empty, and either
the node's role allows "text equivalent from subtree" or the node is not a control and not the
initial node
, then recursively implement this algorithm for each child, starting with step 1.⟲ -
If the text equivalent for this node is still empty,
get it from tooltip for the
current node
if any.
-
If the node is hidden and it's not a part of computation initiated by
- Append space if the space was added at step 1.
- Normalize whitespace, trimming leading and trailing space and condense other whitespace characters into a single space.
Remarks and examples
Item c.
Text equivalent computation from ARIA and native markup is nicely covered by HTML to a11y spec.
Nevertheless as example of a native markup text equivalent can be alt attribute for HTML <img> or a label from <label for> for control element. However, markup for tooltips is not used as native markup text equivalent, they are used as a last resort under item f.
In general name and description don't dupe each other so that if some markup was used as name then it won't be reused as description. For example,
<img title="Me and Eiffel Tower">
Name is "Me and Eiffel Tower", description is empty.
But:
<img alt="I'm in France" title="Me and Eiffel Tower">
Name is "I'm in France", description is "Me and Eiffel Tower".
Item c.i.
Example of
empty on purpose
name is <img alt="">.Item c.ii.
Example of
relation attribute
processing:<button aria-labelledby="span" id="btn" />
<button aria-labelledby="btn" id="btn2" />
<span id="span">text</span>
@id="btn" name is "text",
aria-labelledby
is processed since we don't have reentrances.@id="btn2" doesn't have a name,
aria-labelledby
on @id="btn" is ignored because otherwise it would mean reentrance (@id="btn2" aria-labelledby
brought us here).Note, if the recursion only produces white space then we proceed to the next item of the algorithm. For example
<span id="span"></span>
<button aria-labelledby="span">press me</button>
Name of button element is "press me". The rule is also applicable to item e.
Item d.
1. By user-managed value we assume the
value
of accessible object. In HTML <input> case it's built from value attribute. In case of ARIA that will be aria-valuetext for example.2. If the
current node
is initial node
then value is not included.<div role="slider" aria-valuetext="right in the middle"></div>
Name is empty for ARIA slider.
3. But if the
current node
is not initial node
then value is included.<label for="input">
Position
<div role="slider" aria-valuetext="right in the middle">
</div>
</label>
<input id="input" type="checkbox">
Name of the checkbox is "Position right in the middle".
4. If the
current node
is the initial node
and it was reentered then:a. If the node is in middle of text equivalent computation then its value is included.
<label>
Subscribe to
<select>
<option>ATOM</option>
<option>RSS</option>
</select>
feed.
</label>
Name for select is "Subscribe to ATOM feed".
b. If node is not in the middle of text equivalent computation then value is omitted.
<label>Home page: <input type="text"></label>
Name for input is "Home page:".
nit: Accessilbe -> Accessible ;)
ReplyDeleteI've been told several years ago I should learn how to write this word, otherwise they said whole Mozilla sources will be misspelled :)
DeleteThank you for the catch.
That is a testament to your impact on our source :)
Delete