LibWeb: Fix aria-label precedence in accessible-name computation

This change makes Ladybird give the value of the aria-label attribute
the correct precedence for accessible-name computation required by the
“Accessible Name and Description Computation” and HTML-AAM specs and by
the corresponding WPT tests.

Otherwise, without this change, Ladybird fails some of the WPT subtests
of the test at https://wpt.fyi/results/accname/name/comp_label.html.
This commit is contained in:
sideshowbarker 2024-11-18 04:20:24 +09:00 committed by Sam Atkins
parent 314e5d6bb7
commit 6bfc35b6a9
Notes: github-actions[bot] 2024-11-29 12:19:25 +00:00
3 changed files with 403 additions and 15 deletions

View file

@ -2288,11 +2288,24 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
return element->aria_label().release_value();
return total_accumulated_text.to_string();
}
// C. Embedded Control: Otherwise, if the current node is a control embedded
// within the label (e.g. any element directly referenced by aria-labelledby) for
// another widget, where the user can adjust the embedded control's value, then
// return the embedded control as part of the text alternative in the following
// manner:
// D. AriaLabel: Otherwise, if the current node has an aria-label attribute whose value is not undefined, not
// the empty string, nor, when trimmed of whitespace, is not the empty string:
// AD-HOC: Weve reordered substeps C and D from https://w3c.github.io/accname/#step2 — because
// the more-specific per-HTML-element requirements at https://w3c.github.io/html-aam/#accname-computation
// necessitate doing so, and the “input with label for association is superceded by aria-label” subtest at
// https://wpt.fyi/results/accname/name/comp_label.html wont pass unless we do this reordering.
// Spec PR: https://github.com/w3c/aria/pull/2377
if (target == NameOrDescription::Name && element->aria_label().has_value() && !element->aria_label()->is_empty() && !element->aria_label()->bytes_as_string_view().is_whitespace()) {
// TODO: - If traversal of the current node is due to recursion and the current node is an embedded control as defined in step 2E, ignore aria-label and skip to rule 2E.
// https://github.com/w3c/aria/pull/2385 and https://github.com/w3c/accname/issues/173
if (!element->is_html_slot_element())
return element->aria_label().value();
}
// C. Embedded Control: Otherwise, if the current node is a control embedded within the label (e.g. any element
// directly referenced by aria-labelledby) for another widget, where the user can adjust the embedded control's
// value, then return the embedded control as part of the text alternative in the following manner:
GC::Ptr<DOM::NodeList> labels;
if (is<HTML::HTMLElement>(this))
labels = (const_cast<HTML::HTMLElement&>(static_cast<HTML::HTMLElement const&>(*current_node))).labels();
@ -2372,16 +2385,6 @@ ErrorOr<String> Node::name_or_description(NameOrDescription target, Document con
return builder.to_string();
}
// D. AriaLabel: Otherwise, if the current node has an aria-label attribute whose
// value is not undefined, not the empty string, nor, when trimmed of whitespace,
// is not the empty string:
if (target == NameOrDescription::Name && element->aria_label().has_value() && !element->aria_label()->is_empty() && !element->aria_label()->bytes_as_string_view().is_whitespace()) {
// TODO: - If traversal of the current node is due to recursion and the current node is an embedded control as defined in step 2E, ignore aria-label and skip to rule 2E.
// https://github.com/w3c/aria/pull/2385 and https://github.com/w3c/accname/issues/173
if (!element->is_html_slot_element())
return element->aria_label().value();
}
// E. Host Language Label: Otherwise, if the current node's native markup provides an attribute (e.g. alt) or
// element (e.g. HTML label or SVG title) that defines a text alternative, return that alternative in the form
// of a flat string as defined by the host language, unless the element is marked as presentational

View file

@ -0,0 +1,141 @@
Summary
Harness status: OK
Rerun
Found 131 tests
131 Pass
Details
Result Test Name MessagePass label valid on div with alert role
Pass label valid on div with alertdialog role
Pass label valid on div with application role
Pass label valid on div with article role
Pass label valid on div with banner role
Pass label valid on div with blockquote role
Pass label valid on div with button role
Pass label valid on div with cell role
Pass label valid on div with checkbox role
Pass label valid on div with columnheader role
Pass label valid on div with combobox role
Pass label valid on div with complementary role
Pass label valid on div with contentinfo role
Pass label valid on div with dialog role
Pass label valid on div with directory role
Pass label valid on div with document role
Pass label valid on div with feed role
Pass label valid on div with figure role
Pass label valid on div with form role
Pass label valid on div with grid role
Pass label valid on div with gridcell role
Pass label valid on div with group role
Pass label valid on div with heading role
Pass label valid on div with img role
Pass label valid on div with link role
Pass label valid on div with list role
Pass label valid on div with listbox role
Pass label valid on div with listitem role
Pass label valid on div with log role
Pass label valid on div with main role
Pass label valid on div with marquee role
Pass label valid on div with math role
Pass label valid on div with menu role
Pass label valid on div with menubar role
Pass label valid on div with menuitem role
Pass label valid on div with menuitemcheckbox role
Pass label valid on div with menuitemradio role
Pass label valid on div with meter role
Pass label valid on div with navigation role
Pass label valid on div with note role
Pass label valid on div with option role
Pass label valid on div with progressbar role
Pass label valid on div with radio role
Pass label valid on div with radiogroup role
Pass label valid on div with region role
Pass label valid on div with row role
Pass label valid on div with rowgroup role
Pass label valid on div with rowheader role
Pass label valid on div with scrollbar role
Pass label valid on div with search role
Pass label valid on div with searchbox role
Pass label valid on div with separator role
Pass label valid on div with slider role
Pass label valid on div with spinbutton role
Pass label valid on div with status role
Pass label valid on div with switch role
Pass label valid on div with tab role
Pass label valid on div with table role
Pass label valid on div with tablist role
Pass label valid on div with tabpanel role
Pass label valid on div with textbox role
Pass label valid on div with timer role
Pass label valid on div with toolbar role
Pass label valid on div with tooltip role
Pass label valid on div with tree role
Pass label valid on div with treegrid role
Pass label valid on div with treeitem role
Pass label valid on link element
Pass label valid on article element
Pass label valid on aside element
Pass label valid on blockquote element
Pass label valid on button element
Pass label valid on dl element
Pass label valid on footer element
Pass label valid on fieldset element
Pass label valid on figure element
Pass label valid on form element
Pass label valid on header element
Pass label valid on h1 element
Pass label valid on h2 element
Pass label valid on h3 element
Pass label valid on h4 element
Pass label valid on h5 element
Pass label valid on h6 element
Pass label valid on hr element
Pass label valid on img element
Pass label valid on input type checkbox element
Pass label valid on input type radio element
Pass label valid on input type search element
Pass label valid on input type text element
Pass label valid on listitem element
Pass label valid on main element
Pass label valid on math element
Pass label valid on meter element
Pass label valid on nav element
Pass label valid on list (ordered) element
Pass label valid on section element
Pass label valid on select element
Pass label valid on option element
Pass label valid on table element
Pass label valid on thead element
Pass label valid on th element with the scope of col
Pass label valid on th (scope row) element
Pass label valid on tbody element
Pass label valid on tr element
Pass label valid on td element
Pass label valid on tfoot element
Pass label valid on textarea element
Pass label valid on list (unordered) element
Pass button's hidden referenced name (display:none) supercedes aria-label
Pass button's hidden referenced name (visibility:hidden) supercedes aria-label
Pass button's hidden referenced name (visibility:hidden) with hidden aria-labelledby traversal falls back to aria-label
Pass link's aria-labelledby name supercedes aria-label
Pass img's aria-label supercedes alt attribute
Pass svg's aria-label supercedes title tag
Pass input with label for association is superceded by aria-label
Pass button name from contents is superceded by aria-label
Pass h1 text is superceded by aria-label
Pass button with title is superceded by aria-label
Pass textarea's name with trailing whitespace in aria-label is valid
Pass link's name with leading whitespace in aria-label is valid
Pass button with blank braille pattern has name as such (not treated as whitespace per Unicode standard)
Pass div with role alert and carriage return in aria-label is valid
Pass link's name with tab in aria-label is valid
Pass button with leading form feed control character in aria-label is valid
Pass nav with trailing nbsp char aria-label is valid (nbsp is preserved in name)
Pass button with leading nbsp char in aria-label is valid (and uses aria-label)
Pass button with empty aria-label does not use aria-label as name
Pass textarea with tab character as aria-label does not use aria-label as name
Pass button with carriage return as aria-label does not use aria-label as name
Pass button with space characters as aria-label does not use aria-label as name

View file

@ -0,0 +1,244 @@
<!doctype html>
<html>
<head>
<title>Name Comp: Label</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/testdriver.js"></script>
<script src="../../resources/testdriver-vendor.js"></script>
<script src="../../resources/testdriver-actions.js"></script>
<script src="../../wai-aria/scripts/aria-utils.js"></script>
</head>
<body>
<h1>AccName: Label Tests</h1>
<p>Tests the <a href="https://w3c.github.io/accname/#comp_label">#comp_label</a> portions of the AccName <em>Name Computation</em> algorithm.</p>
<!-- https://www.w3.org/TR/wai-aria/#namefromauthor -->
<!-- Embedded controls tested in ./comp_embedded_control.html -->
<h2>Elements with roles that support aria-label use</h2>
<!-- https://www.w3.org/TR/wai-aria/#namefromauthor -->
<div role="alert" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with alert role" class="ex">x</div>
<div role="alertdialog" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with alertdialog role" class="ex">x</div>
<div role="application" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with application role" class="ex">x</div>
<div role="article" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with article role" class="ex">x</div>
<!-- associationlist and related removed pending: https://github.com/w3c/aria/issues/1662 -->
<div role="banner" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with banner role" class="ex">x</div>
<div role="blockquote" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with blockquote role" class="ex">x</div>
<div role="button" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with button role" class="ex">x</div>
<div role="cell" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with cell role" class="ex">x</div>
<div role="checkbox" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with checkbox role" class="ex">x</div>
<div role="columnheader" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with columnheader role" class="ex">x</div>
<div role="combobox" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with combobox role" class="ex">x</div>
<div role="complementary" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with complementary role" class="ex">x</div>
<div role="contentinfo" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with contentinfo role" class="ex">x</div>
<div role="dialog" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with dialog role" class="ex">x</div>
<div role="directory" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with directory role" class="ex">x</div>
<div role="document" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with document role" class="ex">x</div>
<div role="feed" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with feed role" class="ex">x</div>
<div role="figure" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with figure role" class="ex">x</div>
<div role="form" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with form role" class="ex">x</div>
<div role="grid" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with grid role" class="ex">x</div>
<div role="gridcell" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with gridcell role" class="ex">x</div>
<div role="group" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with group role" class="ex">x</div>
<div role="heading" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with heading role" class="ex">x</div>
<div role="img" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with img role" class="ex">x</div>
<div role="link" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with link role" class="ex">x</div>
<div role="list" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with list role" class="ex">x</div>
<div role="listbox" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with listbox role" class="ex">x</div>
<div role="listitem" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with listitem role" class="ex">x</div>
<!-- listitemkey and listitemvalue pending: https://github.com/w3c/aria/issues/1662 -->
<div role="log" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with log role" class="ex">x</div>
<div role="main" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with main role" class="ex">x</div>
<div role="marquee" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with marquee role" class="ex">x</div>
<div role="math" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with math role" class="ex">x</div>
<div role="menu" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with menu role" class="ex">x</div>
<div role="menubar" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with menubar role" class="ex">x</div>
<div role="menuitem" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with menuitem role" class="ex">x</div>
<div role="menuitemcheckbox" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with menuitemcheckbox role" class="ex">x</div>
<div role="menuitemradio" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with menuitemradio role" class="ex">x</div>
<div role="meter" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with meter role" class="ex">x</div>
<div role="navigation" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with navigation role" class="ex">x</div>
<div role="note" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with note role" class="ex">x</div>
<div role="option" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with option role" class="ex">x</div>
<div role="progressbar" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with progressbar role" class="ex">x</div>
<div role="radio" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with radio role" class="ex">x</div>
<div role="radiogroup" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with radiogroup role" class="ex">x</div>
<div role="region" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with region role" class="ex">x</div>
<div role="row" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with row role" class="ex">x</div>
<div role="rowgroup" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with rowgroup role" class="ex">x</div>
<div role="rowheader" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with rowheader role" class="ex">x</div>
<div role="scrollbar" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with scrollbar role" class="ex">x</div>
<div role="search" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with search role" class="ex">x</div>
<div role="searchbox" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with searchbox role" class="ex">x</div>
<div role="separator" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with separator role" class="ex">x</div>
<div role="slider" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with slider role" class="ex">x</div>
<div role="spinbutton" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with spinbutton role" class="ex">x</div>
<div role="status" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with status role" class="ex">x</div>
<div role="switch" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with switch role" class="ex">x</div>
<div role="tab" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with tab role" class="ex">x</div>
<div role="table" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with table role" class="ex">x</div>
<div role="tablist" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with tablist role" class="ex">x</div>
<div role="tabpanel" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with tabpanel role" class="ex">x</div>
<div role="textbox" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with textbox role" class="ex">x</div>
<div role="timer" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with timer role" class="ex">x</div>
<div role="toolbar" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with toolbar role" class="ex">x</div>
<div role="tooltip" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with tooltip role" class="ex">x</div>
<div role="tree" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with tree role" class="ex">x</div>
<div role="treegrid" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with treegrid role" class="ex">x</div>
<div role="treeitem" aria-label="label" data-expectedlabel="label" data-testname="label valid on div with treeitem role" class="ex">x</div>
<h2>HTML elements that support aria-label</h2>
<!-- aria-label permitted on "all elements of the base markup" with exceptions: https://w3c.github.io/aria/#aria-label -->
<a href="" aria-label="label" data-expectedlabel="label" data-testname="label valid on link element" class="ex">x</a>
<article aria-label="label" data-expectedlabel="label" data-testname="label valid on article element" class="ex">x</article>
<aside aria-label="label" data-expectedlabel="label" data-testname="label valid on aside element" class="ex">x</aside>
<blockquote aria-label="label" data-expectedlabel="label" data-testname="label valid on blockquote element" class="ex">x</blockquote>
<button aria-label="label" data-expectedlabel="label" data-testname="label valid on button element" class="ex">x</button>
<dl aria-label="label" data-expectedlabel="label" data-testname="label valid on dl element" class="ex">
<!-- dt/dd pending listitemkey and listitemvalue roles: https://github.com/w3c/aria/issues/1662 -->
<!-- Currently these map to `term` and `definition` for which name is prohibited. -->
<!-- Using aria-label here would be an authoring error, however whether there is a user agent requirement to ignore the author provided role is still pending https://github.com/w3c/accname/issues/240 -->
<!-- See "Priorities of Constituencies" https://www.w3.org/TR/design-principles/#priority-of-constituencies -->
<dt>x</dt>
<dd>x</dd>
</dl>
<footer aria-label="label" data-expectedlabel="label" data-testname="label valid on footer element" class="ex">x</footer>
<fieldset aria-label="label" data-expectedlabel="label" data-testname="label valid on fieldset element" class="ex">x</fieldset>
<figure aria-label="label" data-expectedlabel="label" data-testname="label valid on figure element" class="ex">x</figure>
<form action="" aria-label="label" data-expectedlabel="label" data-testname="label valid on form element" class="ex">x</form>
<header aria-label="label" data-expectedlabel="label" data-testname="label valid on header element" class="ex">x</header>
<h1 aria-label="label" data-expectedlabel="label" data-testname="label valid on h1 element" class="ex">x</h1>
<h2 aria-label="label" data-expectedlabel="label" data-testname="label valid on h2 element" class="ex">x</h2>
<h3 aria-label="label" data-expectedlabel="label" data-testname="label valid on h3 element" class="ex">x</h3>
<h4 aria-label="label" data-expectedlabel="label" data-testname="label valid on h4 element" class="ex">x</h4>
<h5 aria-label="label" data-expectedlabel="label" data-testname="label valid on h5 element" class="ex">x</h5>
<h6 aria-label="label" data-expectedlabel="label" data-testname="label valid on h6 element" class="ex">x</h6>
<hr aria-label="label" data-expectedlabel="label" data-testname="label valid on hr element" class="ex" />
<img alt="" aria-label="label" data-expectedlabel="label" data-testname="label valid on img element" class="ex" />
<input type="checkbox" aria-label="label" data-expectedlabel="label" data-testname="label valid on input type checkbox element" class="ex"/>
<input type="radio" aria-label="label" data-expectedlabel="label" data-testname="label valid on input type radio element" class="ex" />
<input type="search" aria-label="label" data-expectedlabel="label" data-testname="label valid on input type search element" class="ex" />
<input type="text" aria-label="label" data-expectedlabel="label" data-testname="label valid on input type text element" class="ex" />
<li aria-label="label" data-expectedlabel="label" data-testname="label valid on listitem element" class="ex">x</li>
<main aria-label="label" data-expectedlabel="label" data-testname="label valid on main element" class="ex">x</main>
<math aria-label="label" data-expectedlabel="label" data-testname="label valid on math element" class="ex">x</math>
<meter aria-label="label" data-expectedlabel="label" data-testname="label valid on meter element" class="ex">x</meter>
<nav aria-label="label" data-expectedlabel="label" data-testname="label valid on nav element" class="ex">x</nav>
<ol aria-label="label" data-expectedlabel="label" data-testname="label valid on list (ordered) element" class="ex">x</ol>
<section aria-label="label" data-expectedlabel="label" data-testname="label valid on section element" class="ex">x</section>
<select aria-label="label" data-expectedlabel="label" data-testname="label valid on select element" class="ex">x</select>
<select>
<option aria-label="label" value="foo" data-expectedlabel="label" data-testname="label valid on option element" class="ex">x</option>
</select>
<table aria-label="label" data-expectedlabel="label" data-testname="label valid on table element" class="ex">
<thead aria-label="label" data-expectedlabel="label" data-testname="label valid on thead element" class="ex">
<tr>
<th scope="col" aria-label="label" data-expectedlabel="label" data-testname="label valid on th element with the scope of col" class="ex">x</th>
<th scope="row" aria-label="label" data-expectedlabel="label" data-testname="label valid on th (scope row) element" class="ex">x</th>
</tr>
</thead>
<tbody aria-label="label" data-expectedlabel="label" data-testname="label valid on tbody element" class="ex">
<tr aria-label="label" data-expectedlabel="label" data-testname="label valid on tr element" class="ex">
<td aria-label="label" data-expectedlabel="label" data-testname="label valid on td element" class="ex">x</td>
<td>x</td>
</tr>
</tbody>
<tfoot aria-label="label" data-expectedlabel="label" data-testname="label valid on tfoot element" class="ex">
<tr>
<td>x</td>
<td>x</td>
</tr>
</tfoot>
</table>
<textarea aria-label="label" data-expectedlabel="label" data-testname="label valid on textarea element" class="ex">x</textarea>
<ul aria-label="label" data-expectedlabel="label" data-testname="label valid on list (unordered) element" class="ex">x</ul>
<h2>Name computation precedence tests</h2>
<!-- Name computation: https://w3c.github.io/accname/#computation-steps -->
<!-- Step 2A: Hidden Not Referenced supercedes 2D: AriaLabel, also see wpt/accname/name/comp_hidden_not_referenced.html -->
<button aria-labelledby="span1" aria-label="foo" data-expectedlabel="label" data-testname="button's hidden referenced name (display:none) supercedes aria-label" class="ex">
<span id="span1" style="display:none;">
<span id="span2" style="display:none;">label</span>
</span>
x
</button>
<button aria-labelledby="span3" aria-label="foo" data-expectedlabel="label" data-testname="button's hidden referenced name (visibility:hidden) supercedes aria-label" class="ex">
<span id="span3" style="visibility:hidden;">
<span id="span4" style="visibility:hidden;">label</span>
</span>
x
</button>
<button aria-labelledby="span5" aria-label="foo" data-expectedlabel="foo" data-testname="button's hidden referenced name (visibility:hidden) with hidden aria-labelledby traversal falls back to aria-label" class="ex">
<span id="span5">
<span id="span6" style="visibility:hidden;">label</span>
</span>
x
</button>
<!-- Step 2B: LabelledBy supercedes 2D: AriaLabel, also see wpt/accname/name/comp_labelledby.html -->
<a href="#" aria-labelledby="span7" aria-label="foo" data-expectedlabel="label" data-testname="link's aria-labelledby name supercedes aria-label" class="ex">x</a>
<span id="span7">label</span>
<!-- Step 2C: Embedded Control labelling supercedes 2D: AriaLabel, see wpt/accname/name/comp_embedded_control.html -->
<!-- Step 2E: Host Language Label is superceded by 2D: AriaLabel, also see wpt/accname/name/comp_host_language_label.html -->
<img alt="alt" aria-label="foo" data-expectedlabel="foo" data-testname="img's aria-label supercedes alt attribute" class="ex" />
<svg aria-label="foo" data-expectedlabel="foo" data-testname="svg's aria-label supercedes title tag" class="ex">
<circle cx="5" cy="5" r="4">
<title>circle</title>
</circle>
</svg>
<label for="input1">label</label>
<input type="text" id="input1" aria-label="foo" data-expectedlabel="foo" data-testname="input with label for association is superceded by aria-label" class="ex" />
<!-- Step 2F: Name From Content is superceded by 2D: AriaLabel, also see wpt/accname/name/comp_name_from_content.html -->
<button aria-label="label" data-expectedlabel="label" data-testname="button name from contents is superceded by aria-label" class="ex">x</button>
<!-- Step 2G: Text Node is superceded by 2D: AriaLabel, also see wpt/accname/name/comp_text_node.html -->
<h1 aria-label="label" data-expectedlabel="label" data-testname="h1 text is superceded by aria-label" class="ex">x</h1>
<!-- Step 2H: Recursive Name from Content, see wpt/accname/name/comp_name_from_content.html -->
<!-- Step 2I: Tooltip is superceded by 2D: AriaLabel, also see wpt/accname/name/comp_tooltip.html -->
<button aria-label="label" title="foo" data-expectedlabel="label" data-testname="button with title is superceded by aria-label" class="ex">x</button>
<h2>Empty/whitespace aria-label tests</h2>
<!--
- AccName computation links to the following definition of "Whitespace": https://infra.spec.whatwg.org/#ascii-whitespace
- Generally, if the current node has an aria-label attribute whose value is not the empty string (including when trimmed of whitespace), return the value of aria-label.
Note: PR for computedLabel whitespace trimming in aria-utils.js: https://github.com/web-platform-tests/wpt/pull/42407/files#diff-6870d82f11ff11cf7c7b544756cecfdac2046acbfe2fbb0640e6d415fbf99916
-->
<textarea aria-label="label " data-expectedlabel="label" data-testname="textarea's name with trailing whitespace in aria-label is valid" class="ex">x</textarea>
<a href="#" aria-label=" label" data-expectedlabel="label" data-testname="link's name with leading whitespace in aria-label is valid" class="ex">x</a>
<button aria-label="" data-expectedlabel="" data-testname="button with blank braille pattern has name as such (not treated as whitespace per Unicode standard)" class="ex">my button</button>
<div role="alert" aria-label="
alert message" data-expectedlabel="alert message" data-testname="div with role alert and carriage return in aria-label is valid" class="ex">x</div>
<a href="#" aria-label=" label" data-expectedlabel="label" data-testname="link's name with tab in aria-label is valid" class="ex">x</a>
<button aria-label=" label" data-expectedlabel="label" data-testname="button with leading form feed control character in aria-label is valid" class="ex">my button</button>
<nav aria-label="label&nbsp;" data-expectedlabel="label&nbsp;" data-testname="nav with trailing nbsp char aria-label is valid (nbsp is preserved in name)" class="ex">x</nav>
<button aria-label="&nbsp;label" data-expectedlabel="&nbsp;label" data-testname="button with leading nbsp char in aria-label is valid (and uses aria-label)" class="ex">my button</button>
<button aria-label="" data-testname="button with empty aria-label does not use aria-label as name" data-expectedlabel="my button" class="ex">my button</button>
<textarea aria-label=" " title="title" data-testname="textarea with tab character as aria-label does not use aria-label as name" data-expectedlabel="title" class="ex">textarea contents</textarea>
<button aria-label="
" data-testname="button with carriage return as aria-label does not use aria-label as name" data-expectedlabel="my button" class="ex">my button</button>
<button aria-label=" " data-testname="button with space characters as aria-label does not use aria-label as name" data-expectedlabel="my button" class="ex">my button</button>
<script>
AriaUtils.verifyLabelsBySelector(".ex");
</script>
</body>
</html>