aria-multiselectable Selectable-Descendant CountingWhere the fix lives. The aria-multiselectable best practice (BP 1626) is enforced by several separate Access Engine automatic tests. They do different jobs and only some were touched by ENG-1726:
| Test | What it flags | Touched by ENG-1726? |
|---|---|---|
| 261 | aria-multiselectable on an element whose explicit role is not grid/listbox/tablist/tree/treegrid ("attribute not allowed on this element"). | No — unchanged. |
| 1296 | aria-multiselectable="false" element with more than one child carrying aria-selected="true" or aria-checked="true". | Yes — shares the descendant-counting util. |
| 1297 | Element with an aria-multiselectable attribute that has zero children whose role supports an aria-selected/aria-checked attribute they carry. | Yes — this is the ENG-1726 fix. |
| 1298 | aria-multiselectable="true" element with fewer than two such children. | Yes — shares the descendant-counting util. |
Two things this page keeps separate: (1) whether aria-multiselectable belongs on the element at all (its container role) is the job of test 261, which ENG-1726 did not change; (2) tests 1296/1297/1298 only count selectable descendants. Test 1297 asks: does this aria-multiselectable element have at least one descendant carrying aria-selected/aria-checked on a role that actually supports it?
The shared helper getMultiselectableDescendantsCount counted a descendant only if its data-ae_ar matched a whitelisted role. But data-ae_ar is recorded only from an explicit role attribute (the markup stage does not compute implicit ARIA roles), so a descendant relying on an implicit role — a <tr> (row) or <td> (gridcell) inside a role="grid", a native <option> (option), a native <input type="checkbox">/radio — had data-ae_ar="null" and was invisible to the whitelist. A correctly-built widget could be counted as having zero selectable children → false-positive 1297 (and 1298).
The helper now resolves implicit ARIA roles for a known set of native elements, but only when the element carries no explicit role (data-ae_ar="null"), and it keeps the explicit-role whitelist unchanged. Roles that do not support the attribute (e.g. role="button", or a no-role <span>/<div>/<li>) are still not counted, so the result stays ARIA-spec compliant:
aria-selected implicit: <tr> → row, <option> → option.aria-checked implicit: <option> → option, <input type="checkbox"> → checkbox, <input type="radio"> → radio.<td>/<th> → gridcell / columnheader/rowheader (aria-selected only), but only when the nearest ancestor <table> is role="grid"/treegrid". In a plain table a <td> is a cell (not whitelisted) and is not counted; a <td> whose nearest table is a plain table is not promoted even if a grid sits higher up.Source: src/Tests/TestUtils/testUtil_ariaMultiselectable.js. The container-role question remains entirely with test 261; ownership of a descendant is attributed to its nearest aria-multiselectable ancestor, so nested multiselect containers each get their own count.
aria-multiselectable attribute / not renderedaria-multiselectable (display:none) — not renderedThe container is not rendered (display:none), so it does not get data-ae_vis and is not in 1297's candidate set (which requires [data-ae_vis][data-ae_avat]). Should not be flagged.
aria-multiselectable — attribute absent1297's applicability keys off the presence of the aria-multiselectable attribute. With no such attribute the element never enters scope. Should not be flagged.
<select> (no multiple, no aria-multiselectable)No aria-multiselectable attribute is present, so 1297 does not apply. Should not be flagged.
<select multiple> with <option selected> — no aria-multiselectable attributeA native <select multiple> conveys multi-selectability natively and carries no aria-multiselectable attribute, so 1297 (which keys off that attribute) does not evaluate it. Note also: the HTML selected attribute is not an aria-selected DOM attribute, which is what the engine's selector matches. Should not be flagged.
These containers have selectable children whose explicit role was already on the whitelist, so they passed 1297 before and after ENG-1726 — controls confirming the fix did not regress the explicit path. (They also pass test 261: their role is listbox/grid/tree.)
<li role="option" aria-selected> explicit roleExplicit role="option" (data-ae_ar="option", whitelisted) + aria-selected → counted. 1297 count ≥ 1. Should not be flagged.
<table role="grid"> with <td role="gridcell" aria-selected> explicit role| A1 (selected) | B1 |
| A2 (selected) | B2 |
Explicit role="gridcell" + aria-selected → counted. 1297 count ≥ 1. Should not be flagged.
role="tree" with <li role="treeitem" aria-selected> explicit roleExplicit role="treeitem" + aria-selected → counted. 1297 count ≥ 1. Should not be flagged.
<tr role="row" aria-selected> explicit role| Name | Size |
|---|---|
| report.pdf | 1.2 MB |
| notes.txt | 4 KB |
Explicit role="row" + aria-selected → counted. 1297 count ≥ 1. Should not be flagged.
grid/row/gridcell explicit role| Invoice | Amount | Status |
|---|---|---|
| INV-1001 | $240.00 | Paid |
| INV-1002 | $80.00 | Pending |
Selection on rows and cells with explicit roles → counted. 1297 count ≥ 1. Should not be flagged.
role="option" items explicit roleFully explicit ARIA listbox. 1297 count ≥ 1. Should not be flagged.
In each case the selectable descendants carry no explicit role (data-ae_ar="null") but their implicit role supports the attribute. Pre-fix they were invisible to the explicit-role whitelist → 1297 reported "zero selectable children" (false positive). Post-fix the helper resolves the implicit role for these native elements → counted → 1297 passes. Each mirrors a regression unit test added in the engine PR.
<td aria-selected> — implicit gridcell implicit role| Cell 1 (selected) | Cell 2 |
A bare <td> has data-ae_ar="null". Because its nearest <table> is role="grid", the fix resolves its implicit role to gridcell (whitelisted for aria-selected) → counted. Pre-fix: not matched → false-positive fail. Post-fix: 1297 passes. Container role grid → no 261 finding.
<tr aria-selected> rows — implicit row implicit role| ID | Name | Age |
|---|---|---|
| 1 | John Doe | 30 |
| 2 | Jane Smith | 28 |
| 3 | Bob Johnson | 35 |
Mirrors the engine's ENG-1726 regression test. The <tr> rows have data-ae_ar="null"; the fix resolves their implicit role row → counted. Pre-fix: false-positive fail. Post-fix: 1297 passes.
<th scope="row" aria-selected> — implicit rowheader implicit role| Row head 1 | A2 |
|---|---|
| Row head 2 | B2 |
A bare <th> in a grid resolves to rowheader/columnheader (whitelisted for aria-selected) → counted. Pre-fix: false-positive fail. Post-fix: 1297 passes.
<option aria-selected> — implicit option implicit roleNative <option> elements have data-ae_ar="null" (no explicit role) but an implicit option role → counted. Pre-fix: false-positive fail. Post-fix: 1297 passes. (Note: a no-role <li>/<span> would not count — only the specific native tags with a supporting implicit role are resolved; see the FAIL section.)
<input type="checkbox" aria-checked> — implicit checkbox implicit role also test 261A native <input type="checkbox"> has data-ae_ar="null" but implicit role checkbox (whitelisted for aria-checked) → counted. Pre-fix: false-positive fail. Post-fix: 1297 passes. The aria-multiselectable on role="group" is still flagged by test 261 (group is not grid/listbox/tablist/tree/treegrid) — a separate finding, not 1297.
<input type="radio" aria-checked> — implicit radio implicit role also test 261Native <input type="radio"> resolves to implicit role radio (whitelisted for aria-checked) → counted. Pre-fix: false-positive fail. Post-fix: 1297 passes. (Container role="group" → separate test 261 finding.)
All containers below use aria-multiselectable="true" with zero supported selectable descendants, so the engine reports 1297 (count = 0) and also 1298 (count < 2). The first two are genuinely empty; the rest are the ARIA-spec guards — descendants that carry the attribute but on a role (explicit or implicit) that does not support it.
<p> children — nothing carries aria-selected/aria-checkedJust a paragraph
Another paragraph
No descendant carries aria-selected/aria-checked → count = 0 → flagged. (Role listbox → no 261 finding.) Should be flagged.
<tr> rows carry no aria-selected/aria-checked| ID | Name | Age |
|---|---|---|
| 1 | John Doe | 30 |
| 2 | Jane Smith | 28 |
Mirrors the engine's "negative twin" test. The rows could carry an implicit row role, but none has aria-selected/aria-checked → count = 0 → flagged. Should be flagged.
role="button" descendants carrying aria-selected — button does not support it unsupported role also test 261Mirrors the engine unit test. role="button" (data-ae_ar="button") is not whitelisted and is not one of the implicit-role tags, so the descendants are not counted even though they carry aria-selected → count = 0 → 1297 fails. The bare-<div> container (data-ae_ar="null") is also flagged by test 261. Should be flagged.
<span aria-selected> children — generic role does not support it no supporting roleA no-role <span> has data-ae_ar="null" and is not one of the resolved implicit-role tags (only <tr>/<option>/<td>/<th>/<input> are) → not counted → count = 0 → flagged. (Role listbox → no 261 finding; the bogus aria-selected on a generic element is a separate ARIA-validity concern caught elsewhere.) Should be flagged.
<table aria-multiselectable> with <td aria-selected> — cell, not gridcell implicit role also test 261| A1 | A2 |
Mirrors the engine unit test. The nearest <table> has no role="grid"/treegrid", so a <td> here is an implicit cell — which does not support aria-selected — and is not counted → count = 0 → 1297 fails. The plain <table> (data-ae_ar="null") is also flagged by test 261. Should be flagged.
<td> carries aria-selected — not promoted implicit role
|
Mirrors the engine unit test. The inner <td aria-selected>'s nearest <table> is the inner plain table, so it is a cell, not a gridcell of the outer grid → not counted. The outer grid's only candidate is rejected → count = 0 → flagged. (Note: the outer-grid <td> wrapping the inner table carries no aria-selected.) Should be flagged.
aria-hiddenThe counter only counts data-ae_vis + data-ae_avat descendants. The single aria-selected child is aria-hidden (no data-ae_avat) → excluded; the other has no aria-selected → count = 0 → flagged. Should be flagged.
aria-multiselectable on an element whose explicit role is not grid/listbox/tablist/tree/treegrid (a bare <div>, role="button", role="group", a plain <table>, a <fieldset role="group">, etc.) is flagged by test 261, not 1297. Cases above marked also test 261 carry that separate finding.aria-selected/aria-checked validity. A bogus <span aria-selected> or <div aria-checked> on a generic element is a real problem caught by the ARIA-attribute-validity test — 1296/1297/1298 simply do not count it (its role does not support the attribute), they do not individually flag it.aria-multiselectable="false" element with more than one selected child is flagged by 1296; an aria-multiselectable="true" element with fewer than two supported selectable children is flagged by 1298. Both share the same (now spec-compliant) descendant counter.This page verifies the ENG-1726 fix to the aria-multiselectable selectable-descendant counter shared by tests 1296/1297/1298. The fix makes counting ARIA-spec compliant: a descendant counts only if it carries aria-selected/aria-checked on a role that supports it, resolved by explicit role (whitelist, unchanged) or by implicit role for a known set of native elements that carry no explicit role — <tr>, <option>, <input type="checkbox"/radio">, and <td>/<th> inside a grid/treegrid.
<td>/<tr>/<th>, native <option>, native checkbox/radio) were pre-fix false positives and now pass.role="button", no-role <span>, and plain-table/nested-table <td> (a cell, not a gridcell) — none of which support the attribute.aria-multiselectable attribute, or not rendered) are outside 1297's scope.