Skip to content

Update: add mapping tables for customizable select#2369

Open
scottaohara wants to merge 18 commits into
mainfrom
select-select-button
Open

Update: add mapping tables for customizable select#2369
scottaohara wants to merge 18 commits into
mainfrom
select-select-button

Conversation

@scottaohara
Copy link
Copy Markdown
Member

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.

  • "author MUST" tests:
  • "user agent MUST" tests:
  • Browser implementations (link to issue or commit):
    • WebKit:
    • Gecko:
    • Blink:
  • Does this need AT implementations?
  • Related APG Issue/PR:
  • MDN Issue/PR:

@netlify
Copy link
Copy Markdown

netlify Bot commented Nov 1, 2024

Deploy Preview for wai-aria ready!

Name Link
🔨 Latest commit df2b946
🔍 Latest deploy log https://app.netlify.com/projects/wai-aria/deploys/68c044808815d30008ad69eb
😎 Deploy Preview https://deploy-preview-2369--wai-aria.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread html-aam/index.html Outdated
@scottaohara scottaohara marked this pull request as draft November 1, 2024 22:12
scottaohara added a commit that referenced this pull request Jan 29, 2025
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
Copy link
Copy Markdown

@mfreed7 mfreed7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Comment thread html-aam/index.html
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html
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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)?

@scottaohara scottaohara marked this pull request as ready for review February 18, 2025 18:29
Comment thread html-aam/index.html Outdated
pkra pushed a commit that referenced this pull request Mar 7, 2025
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
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
<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>
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

provide direct link to the select element in HTML, here

Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Comment thread html-aam/index.html Outdated
Copy link
Copy Markdown
Contributor

@giacomo-petri giacomo-petri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread html-aam/index.html

<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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread html-aam/index.html
<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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. 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.
  2. 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this is a pain point.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My humble proposal:

  • If the select initially has a valid content model, and then an invalid child is added, it should remain a listbox with unspecced behavior, just like how a non-group/option child would affect an explicit aria listbox.
  • If the select initially has an invalid content model its role would be a dialog. All select children would get generic roles. The dialog role is immutable and won't change to a listbox if the invalid children are removed.

Comment thread html-aam/index.html
<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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread html-aam/index.html
<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>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. 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.
  2. 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.

Comment thread html-aam/index.html
<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.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>&nbsp</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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>

@spectranaut spectranaut moved this from Needs Review to Needs updates from review in ARIA Normative PR Tracking Jan 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Needs updates from review

Development

Successfully merging this pull request may close these issues.

7 participants