Update: add mapping tables for customizable select#2369
Conversation
✅ Deploy Preview for wai-aria ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
closes #2382 and is related to #2344 / #2369 This PR adds aria-valuetext as a supported property for the combobox role. the `aria-valuetext` definition is slightly updated to indicate that the attribute can be used on other supported roles. I'm not sure if we want to do any further updates to that section in this PR - or if that really should be handled in a larger PR to resolve #711
| it does not serve as a submit, reset, or generic 'button' type. Rather, | ||
| its purpose is directly tied to the rendering of a customized select | ||
| serving as the visible indicator/styleable node to serve as the | ||
| invoking element for the select's listbox popup. |
There was a problem hiding this comment.
Do you want to mention that the UA stylesheet applies interactivity: inert to this button, to ensure that this comment is true (modulo developer shenanigans)?
closes #2382 and is related to #2344 / #2369 This PR adds aria-valuetext as a supported property for the combobox role. the `aria-valuetext` definition is slightly updated to indicate that the attribute can be used on other supported roles. I'm not sure if we want to do any further updates to that section in this PR - or if that really should be handled in a larger PR to resolve #711
| <p> | ||
| The calculated role of the customizable `select` element's popup picker is a `listbox`, by default.</p> | ||
| <p> | ||
| If authors include invalid elements (according to the the `select` element's content model) as descendants of the `select` element, and those invalid elements result in accessible objects being present as siblings in the accessibility tree to the valid descendent elements of the select, then user agents SHOULD expose the popup picker with the role dialog in the modeless state.</p> |
There was a problem hiding this comment.
provide direct link to the select element in HTML, here
giacomo-petri
left a comment
There was a problem hiding this comment.
For the "generic" button element (which is out of scope for this PR), should we label it as "button (with no parent select element)" or something similar? This would keep it consistent with similar scenarios and help ensure readers don't mistakenly stop here if they have a button within a select.
|
|
||
| <p class=note>Treating the picker as a `dialog` can help inform users that content beyond the expected elements of a `listbox` popup are present, as they can then inspect the content of the dialog with their assistive technology to discover such content.</p> | ||
|
|
||
| <p>See also <a href="#el-button-select-child">`button` element as a child of a `select` element.</p> |
There was a problem hiding this comment.
For better readability, should we move (or duplicate) the link to the 'button as a child of a select element' section closer to the second bullet point in the accessible name computation? It might help readers understand, for example, why an aria-label set on the button doesn’t contribute to the accessible name computation.
| <p> | ||
| The calculated role of the customizable `select` element's popup picker is a `listbox`, by default.</p> | ||
| <p> | ||
| If authors include invalid elements (according to the the `select` element's content model) as descendants of the `select` element, and those invalid elements result in accessible objects being present as siblings in the accessibility tree to the valid descendent elements of the select, then user agents SHOULD expose the popup picker with the role of `dialog` in the modeless state.</p> |
There was a problem hiding this comment.
Implementation requirements that depend on content model are unusual. Browsers typically don't include conformance checkers, so can't easily tell if the content model is being violated or not. What is the purpose here?
There was a problem hiding this comment.
thanks for pointing this out @zcorpan
the rational here was talked about a lot in open ui, but the high level gist is that since the parsing for select was changed to allow for anything, the role of the popup needs to let users know whether they're interacting with a version that follows the content model (and thus can be exposed as a listbox) or has elements in it which are important to make AT users aware of / doesn't follow the content model, and thus was decided to be exposed as a dialog to help surface this to users.
with that said though, i talked with @mfreed7 about this and we were thinking that to mitigate this explicit reference to the content model, we this can be updated to more overtly call out what HTML elements / allowed implicit roles will allow for the default role=listbox, and how the inclusion of others would result in the popup needing to be role=dialog.
There was a problem hiding this comment.
While I understand why it's being proposed, this is the part of customisable select accessibility that worries me the most.
Mutations are a big concern here. What if the <select> started out entirely valid when it was first rendered, but then an author added more elements such that it became invalid? Or on the flip side, what if it were invalid and then became valid? Since we're effectively talking about UA repair for invalid authoring, it's not super important how we fail, but the failure mode needs to be clearly defined. This can't be undefined (unspecified) behaviour if we want interoperable implementations that don't later cause web compat pain.
Perhaps we could state that the role is determined based on the initial rendering of the <select>. If it starts out as valid and an author later makes it invalid, that's their loss. We'll only correct for authoring error to a point. I think this would be the most pragmatic solution and would be the least likely to cause implementation pain and performance problems.
If we do want to handle mutations from valid to invalid and vice versa, there are some difficult issues we need to address:
- Most accessibility APIs don't have role change events (or at least not role change events that clients heed). Should the role just mutate silently, risking confusing the client, or should the subtree be recreated whenever validity changes? Recreating subtrees is expensive all the way through the accessibility stack, particularly if there are a lot of nodes. Even mutating the role silently has performance costs; see below.
- Checking whether validity has changed is not trivial. Unless I'm missing something, we'd need to re-evaluate this every time a descendant is added to a select. At the very least, this probably means walking the ancestry for every insertion or removal, since caching a select ancestor on every node would waste a lot of memory. Anything that adds even the tiniest bit of work for all insertions into the tree, even if it's just an ancestor walk with a simple check, is a potential performance cliff. This possibly also means walking all the non-generic children of the select as well, though we could maybe get around this caching the validity state on the select. In general, any specified behaviour here needs to take performance concerns into account.
CC @eeejay for awareness and input, since he will likely be doing the Gecko implementation for this and has also done some recent work regarding role calculation. CC also @lucasradaelli from Chrome accessibility, since aleventhal is no longer working on that.
There was a problem hiding this comment.
In the hypothetical here that the select has a mix of invalid elements and option elements, the role would be a dialog. But I am unclear of how a platform API or AT would deal with option accessibles that are children of dialog and have no listbox ancestor.
There was a problem hiding this comment.
My humble proposal:
- If the
selectinitially has a valid content model, and then an invalid child is added, it should remain alistboxwith unspecced behavior, just like how a non-group/optionchild would affect an explicit arialistbox. - If the
selectinitially has an invalid content model its role would be a dialog. Allselectchildren would get generic roles. Thedialogrole is immutable and won't change to alistboxif the invalid children are removed.
Initial draft of select / button as child of a select mappings.
0208cd4 to
df2b946
Compare
| <p>To calculate the accessible value of a `select` element:</p> | ||
| <ol> | ||
| <li>If `aria-valuetext` is specified on the `select` element, use the attribute's value, including the empty string.</li> | ||
| <li>Else if there is a `button` part, calculate the accessible value from a non-empty string <a data-cite="accname-1.2/#mapping_additional_nd_te">text equivalent computation</a> of the subtree of that element.</li> |
There was a problem hiding this comment.
Is there anything in the HTML spec that prevents the author from putting something other than the value in the button part? For example, what if the author puts a label in the button part? It would be very weird to expose a label as the value. Obviously, we can't stop authors from doing this, but I wonder if they should at least be warned against it, though that probably belongs in the HTML spec itself.
| <p> | ||
| The calculated role of the customizable `select` element's popup picker is a `listbox`, by default.</p> | ||
| <p> | ||
| If authors include invalid elements (according to the the `select` element's content model) as descendants of the `select` element, and those invalid elements result in accessible objects being present as siblings in the accessibility tree to the valid descendent elements of the select, then user agents SHOULD expose the popup picker with the role of `dialog` in the modeless state.</p> |
There was a problem hiding this comment.
While I understand why it's being proposed, this is the part of customisable select accessibility that worries me the most.
Mutations are a big concern here. What if the <select> started out entirely valid when it was first rendered, but then an author added more elements such that it became invalid? Or on the flip side, what if it were invalid and then became valid? Since we're effectively talking about UA repair for invalid authoring, it's not super important how we fail, but the failure mode needs to be clearly defined. This can't be undefined (unspecified) behaviour if we want interoperable implementations that don't later cause web compat pain.
Perhaps we could state that the role is determined based on the initial rendering of the <select>. If it starts out as valid and an author later makes it invalid, that's their loss. We'll only correct for authoring error to a point. I think this would be the most pragmatic solution and would be the least likely to cause implementation pain and performance problems.
If we do want to handle mutations from valid to invalid and vice versa, there are some difficult issues we need to address:
- Most accessibility APIs don't have role change events (or at least not role change events that clients heed). Should the role just mutate silently, risking confusing the client, or should the subtree be recreated whenever validity changes? Recreating subtrees is expensive all the way through the accessibility stack, particularly if there are a lot of nodes. Even mutating the role silently has performance costs; see below.
- Checking whether validity has changed is not trivial. Unless I'm missing something, we'd need to re-evaluate this every time a descendant is added to a select. At the very least, this probably means walking the ancestry for every insertion or removal, since caching a select ancestor on every node would waste a lot of memory. Anything that adds even the tiniest bit of work for all insertions into the tree, even if it's just an ancestor walk with a simple check, is a potential performance cliff. This possibly also means walking all the non-generic children of the select as well, though we could maybe get around this caching the validity state on the select. In general, any specified behaviour here needs to take performance concerns into account.
CC @eeejay for awareness and input, since he will likely be doing the Gecko implementation for this and has also done some recent work regarding role calculation. CC also @lucasradaelli from Chrome accessibility, since aleventhal is no longer working on that.
| <p> | ||
| In the event invalid elements are present, but are not rendered, then no user agent role repair is necessary.</p> | ||
| <p> | ||
| In the event that invalid elements are present, but are empty, include only whitespace, or are only used as wrapping elements for the valid descendent element's of a select, then user agents SHOULD ignore these elements in the accessibility tree. |
There was a problem hiding this comment.
This is even more concerning. It's probably feasible to do this for empty elements in the initially rendered subtree. It's slightly trickier (but probably still feasible) to do this when new empty elements are inserted into an otherwise valid select. But what if someone inserts an empty <article> into a <select> (so it's ignored), but later inserts a child that makes the <article> invalid? Now we're not just making decisions based on the type of the element. The decisions also have to take into account the contents of that element. That means we're doing even more walk on every insertion into the tree.
Also, does "include only whitespace" explicitly refer to direct children or is this suggesting that we need to evaluate the contents overall. For example, does <article><span> <span> </span></span></article> get ignored or not? What about <article> </article>? I'm guessing this is only intended to cover cases like <article> </article>, but this probably needs to be clarified. Even just saying "includes only a single whitespace child" is probably sufficient clarification.
There was a problem hiding this comment.
I'm not sure why empty invalid tags are an exception here. What is the use-case?
In my proposal above, I could see an empty invalid tag as a method of insuring the picker gets a role of dialog even if there is no initial content, eg:
<select>
<button>
<selectedcontent>Select a pet:</selectedcontent>
</button>
<article></article>
</select>
Initial draft of select / button as child of a select mappings.
Test, Documentation and Implementation tracking
Once this PR has been reviewed and has consensus from the working group, tests should be written and issues should be opened on browsers. Add N/A and check when not applicable.