Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AccName Role Traversal Proposal #1821

Open
accdc opened this issue Oct 4, 2022 · 60 comments
Open

AccName Role Traversal Proposal #1821

accdc opened this issue Oct 4, 2022 · 60 comments
Assignees
Milestone

Comments

@accdc
Copy link
Contributor

accdc commented Oct 4, 2022

As we spoke of during the last ARIA meeting, there needs to be a way of defining synchronicity between the ARIA spec and the AccName spec regarding which roles are recursively traversed.

Since the time when this topic was first discussed, reference
https://lists.w3.org/Archives/Public/public-aria/2017Jun/0057.html
This level of definition was never added to the ARIA spec, even though browsers such as Chrome and others already have logic for this built into their AccName implementations.

As a result of this, it was exceedingly difficult to find a way of adding this to the AccName spec because there was no supported grouping mechanism within the ARIA spec to validate implementation. Unofficially, whether or not a role supported “name from content” was referenced instead for this logic within the ARIA spec within step 2H by referring back to step 2F, but this has led to additional confusion because there are times when roles must be traversed even if they don’t support name from content, and there is no way of definitively saying it should be one way or another given the lack of definition within the ARIA spec. This leads to additional disagreement and makes it impossible to achieve interoperability, which is what the specs strive to achieve.

Since the current grouping mechanism of whether or not a role supports “name from content” is not sufficient for this purpose, a new mechanism needs to be added that can provide this additional level of specificity. This will make it possible to easily add logic to the AccName algorithm to refer back to this grouping mechanism within the ARIA spec to identify which role should or should not be traversed and under which circumstances.

Currently, at the end of each role section in the ARIA spec is a table that defines whether that role supports “name from content”.

I propose to add a new row to that same table that defines whether the role is “Traversable”.

Traversable would support 3 values, “Always”, “Never”, and “When Focusable”.

The word “Traversable” would need to be added to the Terms list within the ARIA spec to specify its purpose. E.G. To specify whether or not the content of a role is traversable within the AccName computation and under which circumstances. (Or whatever…)

These three values (Always, Never, and When Focusable) match the functional criteria that is built into the browsers based on prior agreements when this was discussed in the past.

The meanings of Always and Never are clear in context, though it is important to note that the value When Focusable refers to the circumstance when either the role or one of its ancestor elements is focusable. This definition is not the same as saying that the role is traversable only when the role receives focus. This definition is meant to define that it will be traversable in all cases when the role or one of its ancestor elements is focusable regardless where focus resides.

Officially defining these within the ARIA spec will remove any ambiguity and ensure future interoperability as each spec evolves.

The following role list mostly matches what was originally discussed for this purpose, which includes updates to the ARIA spec and relevant guidance since then. It can be modified as needed to ensure agreement between implementors.

Always Traverse

button, checkbox, heading, link, menuitem, menuitemcheckbox, menuitemradio, option, radio, slider, switch, tab, tooltip, treeitem

Never Traverse

alert, alertdialog, application, article, banner, complementary, dialog, document, feed, figure, form, grid, img, listbox, log, main, marquee, math, menu, menubar, navigation, radiogroup, region, search, searchbox, separator, tablist, tabpanel, textbox, timer, toolbar, tree, treegrid

Traverse Only When Focusable

cell, columnheader, combobox, gridcell, contentinfo, definition, directory, group, list, note, row, rowgroup, rowheader, scrollbar, spinbutton, status, table, term

As noted, the above lists are not set in stone and we can hammer out which ones we can all agree on. (I may have overlooked a role so please suggest where to add if so.)

After this is added to the ARIA spec, it will then be possible to add a relatively simple step to the AccName algorithm to handle cases of whether or not a role is traversable and refer back to whether it is either “Always”, “Never”, or only “When Focusable”.

Feedback is welcome.

All the best,
Bryan

@accdc accdc added the Agenda label Oct 4, 2022
@scottaohara
Copy link
Member

appreciate you outlining all this, as it's giving me something to wrap my head around in a much easier way. Though with that said, in regards to the above i'm unclear what would happen with the following use case i mentioned in the our last WG meeting

<a href=...>
  <article>
     content goes here
  </article>
</a>

i see article is mentioned as never traversable, so, would this not still produce a link without an accessible name? if so, maybe there needs to be another designation? Unless "only when focusable" doesn't necessarily refer just to the element, if focusable, but also a parent/ancestor element that would be nameless otherwise?

I realize you said that the lists are not set in stone, but yeh, i'm not sure i understand how some roles like banner or article are in one category, but contentinfo and group are in another.

Thanks again for the work on this Bryan. Regardless of my questions/comments above, i'm sure this'll help move us forward.

@accdc
Copy link
Contributor Author

accdc commented Oct 4, 2022

Actually article was part of the list originally proposed by Aaron back in 2017, which is what I am basing this list on mainly since I don't have time to take the Chrome code apart to see what it's doing.

If others in the group agree to move this into the When Focusable category, I will abide by whatever people can agree on. The same goes with the rest of the roles.

@jnurthen
Copy link
Member

jnurthen commented Oct 4, 2022

Where is generic in this list?

@accdc
Copy link
Contributor Author

accdc commented Oct 4, 2022

That's one I forgot, generic should be in the Always category.

@jnurthen
Copy link
Member

jnurthen commented Oct 4, 2022

The third category in Chrome is:
// ----- Conditional: contribute to ancestor only, unless focusable -------
// Some objects can contribute their contents to ancestor names, but
// only have their own name if they are focusable
Why the deviation from this in this proposal?

@accdc
Copy link
Contributor Author

accdc commented Oct 4, 2022

I was mainly thinking of screen readers like JAWS that use a virtual buffer model that does not follow focus.

If this were changed to only when it receives focus, it would break Scott's example in all cases such as when pressing Insert+F7 to get a list of all links on the page.

@jnurthen
Copy link
Member

jnurthen commented Oct 4, 2022

So there are 2 parts to this. Roles that can have their own accessible name and roles that can only contribute to an ancestor's accessible name (for 2F). We need to cover both parts of this.

@accdc
Copy link
Contributor Author

accdc commented Oct 5, 2022

"So there are 2 parts to this. Roles that can have their own accessible name and roles that can only contribute to an ancestor's accessible name (for 2F)."

As far as I know this is already covered. "Name from author" already specifies if a role is namable, "Name from content" specifies if it can receive a general name using it's content, and "Traversable" would only specify if it can be traversed in 2F.

@jnurthen
Copy link
Member

jnurthen commented Oct 5, 2022

In case it helps I exported https://searchfox.org/mozilla-central/source/accessible/base/RoleMap.h#1 into a google sheet at https://docs.google.com/spreadsheets/d/1iLk-KTX2PZvqIhdhQzM9vfMI3za3RlWQCRNx1e6m2VM/edit?usp=sharing
The last column contains the mozilla accessible name categorization for each role which is one of the following:

  1. eNameFromSubtreeIfReqRule
  2. eNameFromSubtreeRule
  3. eNameFromValueRule
  4. eNoNameRule

I could look through the code to work out exactly what each of these means but maybe @jcsteh can fill this in.

@jcsteh
Copy link

jcsteh commented Oct 5, 2022

The last column contains the mozilla accessible name categorization for each role which is one of the following:

1. eNameFromSubtreeIfReqRule

This effectively maps to Name from: author, Traversable: always.

2. eNameFromSubtreeRule

This effectively maps to Name from: content, Traversable: always.

3. eNameFromValueRule

This deals with 2C of the AccName spec:

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

4. eNoNameRule

This effectively maps to Name from: author (or prohibited), Traversable: never.

it is important to note that the value When Focusable refers to the circumstance when either the role or one of its ancestor elements is focusable.

Note that Gecko does not currently support this concept at all. Overall, I think it makes sense. However, one problem is that "focusable" can mean a few different things:

  1. The element is tabbable. Traversing definitely makes sense in this case.
  2. The element is explicitly focusable but not tabbable; i.e. tabindex="-1". It probably makes sense to traverse in this case, but this gets muddy when combined with 3) below.
  3. The element is scrollable. In Gecko, this means that it will be tabbable so that a keyboard user can scroll the element. In Chromium, this currently isn't the case, though I heard that this might change in future. It probably doesn't make sense to traverse in this case, as that could result in ridiculously long names for large containers. To make things more complicated, some authors apply tabindex="-1" to prevent this from being tabbable, at which point 2) applies and it still probably doesn't make sense to traverse for the same reason.

@jcsteh
Copy link

jcsteh commented Oct 5, 2022

FWIW, I don't think we could reasonably support Traversable: when focusable in Gecko until this issue is sorted out.

@accdc
Copy link
Contributor Author

accdc commented Oct 7, 2022

Since this is simply a proposal, I expected some shifting based on backend limitations. If "When Focusable" were changed to "When Focused To", would you be able to support it?

@JAWS-test
Copy link
Contributor

JAWS-test commented Oct 11, 2022

I think the problem is more complex and the following things should be clarified in AccName:

  • which roles are transparent in the sense that on the one hand an AccName is determined but on the other hand the content is perceptible when reading with the virtual cursor (currently transparent are e.g. the roles main and table, but not the roles button and link; for link a change would make sense to support e.g. linked tiles, where on focus only the AccName is output, but on reading the whole tile content is perceptible) (related: Consider prohibiting author naming certain elements html-aam#160 (comment)).
  • what are the rules regarding transparency for elements where I cannot use a virtual cursor (inside role=menu, role=application) or where I assume that I should not use a virtual cursor (e.g. inside role=grid, role=listbox, role=tablist)? I think in these cases the whole content should be output as AccName.
  • which roles serve as group labels for child element (currently e.g. role=group; but here there was the strange Chrome/Edge bug that a div with tabindex=-1 suddenly is an element with semantics and therefore the whole text content was output as group label - the cause was probably the Presentational Roles Conflict Resolution (related: Which roles serve as group names and descriptions? #1710)
  • what are the rules when an element has no label. For example, if we say a div must not have a label and in a link there is text and a div, then it may make sense to use only the text as the link label and not the div. But if a link contains only a div, then in any case the text content of the div should be used as the link label. But that I use only the text and not the div in the link with text and div as AccName, is only ok if I define beforehand 1. the transparency rules when reading with the virtual cursor and 2. exception rules, what happens when I have no virtual cursor (if the link is in an application with role=application, then always the text and the content of the div should serve as link label).

However, the rules outlined here are probably too complex, on the one hand, to implement consistently in browsers and, on the other hand, for web developers to apply them correctly. It would be much simpler to abandon the concept that an element cannot have an AccName and say that the text content is always the AccName (for elements that do not have Name from Author, like a div).

@jcsteh
Copy link

jcsteh commented Oct 11, 2022

If "When Focusable" were changed to "When Focused To", would you be able to support it?

It would be easier to support, but I don't think it's what we want. Whether something is focused is a lot more transient than whether something is focusable. Thus, the name would potentially change quite often, requiring a lot of extra name change events.

On further reflection, I also realised I misunderstood the purpose of this "when focusable" rule. If I'm reading your proposal correctly, you're suggesting this only relates to aria-labelledby/describedby traversals and not "Name from: content". I'm curious as to why we want something to be traversed when focusable for aria-labelledby/describedby, but not not when calculating name from content. For aria-labelledby/describedby, I would've thought they should just always be traversed for those roles, whereas we probably do want them to be included in name from content only when focusable.

@accdc
Copy link
Contributor Author

accdc commented Oct 12, 2022

I don't know what to do with this then.

This is not just for aria-labelledby and aria-describedby traversals, but for any child node traversal that involves step 2H.

We have to find a way of documenting how this is implemented in the browsers, because currently the only thing the spec says is to recursively start at 2F.i when traversing all child nodes, and this will not work correctly for all element and role types.

E.G. A heading is a simple example of why, for example if it includes an embedded menu that is rendered inline with a triggering element within the heading. Also a tree using the same concept, or a standard select element such as a country selector that has over 280 options within it.

If you apply 2H as it is currently written, skipping only to 2F.i, then name from content is skipped and everything must be included as the heading name regardless what type of role it is.

Is this really what you want to happen?

@jcsteh
Copy link

jcsteh commented Oct 13, 2022

Let's put aside the precise definition of focusable, focused, etc. for a moment.

  1. I think having always traversable and never traversable makes sense. However, I think the focusable concept is only relevant when computing the name for the element itself, not for descendant traversal. That is, for aria-labelledby, aria-describedby and descendant traversal, we should only look at always traversable or never traversable.
  2. We should have an additional list of roles that do allow name from content when they're focusable. This is effectively a repair mechanism if the author didn't specify a name when they should have. Btw, it is this repair mechanism that Chrome currently implements but Firefox does not.

@accdc
Copy link
Contributor Author

accdc commented Oct 15, 2022

We spoke about this at the last ARIA meeting, and I think it would be beneficial for us to have a deep dive meeting to hash out what is or is not possible from the implementer perspective and the issues being addressed. Would you @jcsteh be willing to attend that? Ideally this would also include @aleventhal and @cookiecrook as well so we can work this out.

@jcsteh
Copy link

jcsteh commented Oct 16, 2022

The main feasibility question regarding implementation relates to the definition of focusable. The rest all seems feasible once we flesh out the details. Regardless, I'd be happy to discuss this in a deep dive meeting if we can make the time zones play ball.

@accdc
Copy link
Contributor Author

accdc commented Oct 21, 2022

Thanks, that would help a lot for all of us to be on the same page.

Here are some possible dates and times for us to do this. I apologize in advance, this is California Pacific time where I live because I'm not sure of the time zones of everyone involved.

Thursday October 27: 4:00-5:00 PM PST.
Thursday November 3: 4:00-5:00 PM PST.
Thursday November 10: 4:00-5:00 PM PST.

Everyone in the WG is welcome, though these are the specific participants that I will need to attend for this to be productive.
@jcsteh
@cookiecrook
@aleventhal
@scottaohara

Can all of you please confirm which dates will work for your schedule?

@MelSumner
Copy link
Contributor

Per Meeting Zone

A Thursday at 4:00 PM PST works out to be 6:00 PM CST, 7:00 PM for EST, and Friday 10 AM in Australia.

@accdc
Copy link
Contributor Author

accdc commented Oct 25, 2022

Awesome thanks!

@jcsteh , @aleventhal , @cookiecrook , @scottaohara This Thursday, for example, works great for me. (hint hint...) ;)

@jcsteh
Copy link

jcsteh commented Oct 25, 2022

All of those dates work for me at this stage.

Just to clarify (largely as a note to self), it's 9AM Brisbane/Queensland time, since Queensland doesn't have DST but NSW/Vic do because silly reasons.

@scottaohara
Copy link
Member

nov 4 or the 10th are fine by me

@accdc
Copy link
Contributor Author

accdc commented Nov 1, 2022

Hi @jcsteh
It looks like we are all good to go for this Thursday (November 3) at 4:00PM California Pacific time. I think that would be 9:00AM on the 4th your time?
I'll assume this works for you and ask @jnurthen if he can setup the meeting invite unless you say it won't work on your end.
Hopefully talk soon! :)

@jcsteh
Copy link

jcsteh commented Nov 1, 2022

That time works for me. Thanks.

@spectranaut spectranaut removed the Agenda label Nov 8, 2022
@spectranaut
Copy link
Contributor

This was discussed in a deep dive: https://www.w3.org/2022/11/03-aria-dive-minutes

@jcsteh
Copy link

jcsteh commented Nov 9, 2022

During the deep dive call, I said I'd provide a summary of my proposal. Looking back at all the comments in this issue, I think my proposal is simply to take the original proposal made by @accdc in #1821 (comment) except for the focusable part. That is, we add traversable: always and traversable: never, but not traversable: focusable. Because we're only applying this to recursive traversal (2H), whether the element is focusable shouldn't be relevant. Is there any reason this is problematic? I couldn't establish one on the call.

Of course, there's still a lot to debate as to which roles are traversable. I acknowledge the article inside link example, but making article traversable feels kinda nasty given that an article potentially suggests a great deal of content.

Separately, we probably do need a concept for roles which calculate name from content when they're focusable, but don't do this when not focusable. Chromium has this concept as noted in #1821 (comment), but Gecko currently doesn't. I'm not sure about WebKit. In any case, I think this should be handled separately from recursive traversal.

I also said I'd dig into the situation with group, which is listed as a role that Gecko traverses recursively but has a specific exception for treeitems. Group was added as a recursively traversable role in https://bugzilla.mozilla.org/show_bug.cgi?id=1616851 because Gmail messages are a cell containing a tbody with display: block which gets mapped to the group role (since it's a row group). That tbody contains details about the sender, etc., so it needed to be included. However, it looks like something in the markup or Gecko has changed there and there doesn't seem to be an intervening group any more, so maybe we can remove that anyway.

@jcsteh
Copy link

jcsteh commented Feb 1, 2024

Okay. Over a year late - I'm really sorry - but better late than never I guess. 😳

As requested, I've taken a first stab at drafting these lists. I considered various parts of the spec and what browsers are currently doing, and garnished it with a bit of my own opinion. :) I was only able to look at Gecko and Chromium, so WebKit is missing from this analysis.

  • Always Traverse: button, caption, cell, checkbox, code, columnheader, definition, deletion, emphasis, generic, heading, insertion, link, listitem, mark, menuitem, menuitemcheckbox, menuitemradio, meter, note, option, paragraph, radio, row, rowheader, slider, strong, subscript, superscript, switch, tab, term, time, tooltip, treeitem
  • Never Traverse: alert, alertdialog, application, article, banner, blockquote, combobox, comment, complementary, contentinfo, dialog, document, feed, figure, form, grid, group, image/img, listbox, log, main, marquee, math, menu, menubar, navigation, progressbar, radiogroup, region, scrollbar, search, searchbox, separator, slider, spinbutton, status, suggestion, table, tablist, tabpanel, textbox, timer, toolbar, tree, treegrid

Gecko and Chromium currently disagree on a few of these:

  • directory: Gecko doesn't traverse, Chromium does. Directory is basically the same as list and both traverse for list, so I think Chromium should change here. That said, it's a deprecated role, so we shouldn't waste time on it.
  • feed: Gecko traverses, Chromium doesn't. I think Gecko should change here.
  • form: Gecko doesn't traverse, Chromium does. I think Chromium should change here, especially since it doesn't traverse for other landmarks.
  • group: Gecko traverses, Chromium doesn't. I think Gecko should change here. See AccName Role Traversal Proposal #1821 (comment) for background.
  • log: Gecko traverses, Chromium doesn't. Gecko should change here.
  • note: Gecko traverses, Chromium doesn't. I really don't care much, but in the absence of a stronger argument, I'd say Chromium should change here, since it does traverse for paragraph.
  • table, grid: This case is confusing. Gecko always traverses these. Chromium doesn't, except that when you use an HTML <table> without ARIA, it does. I wanted to agree with @accdc that we shouldn't traverse them, except that it seems that @joanmarie very deliberately implemented this in Gecko, which makes me think there was a good reason to traverse these. So, this one needs some careful discussion.
  • term: Gecko will traverse (when support lands), Chromium doesn't. I feel Chromium should change here, since it does traverse for definition.
  • timer: Gecko traverses, Chromium doesn't. Gecko should change here.
  • Chromium has some interesting behaviour where even for roles it doesn't traverse when walking descendants, it still traverses them when they're inside a subtree referenced with aria-labelledby. For example:
    data:text/html,<button aria-labelledby="doc"></button><div id="doc" role="document">a<article>b<div role="application">c
    Chromium labels the button "a b c". This makes things inconsistent and seems wrong to me. For one thing, it could result in extremely long labels. On the other hand, I guess the thinking is that if something is targeted by aria-labelledby, the author intended it to have a label. Still, I think this needs some discussion.

@joanmarie
Copy link
Contributor

it seems that @joanmarie very deliberately implemented this in Gecko, which makes me think there was a good reason to traverse these.

Looking at the code comment I wrote, and the date of the commit, there's a good chance the reason was to get AccName 1.1 to rec and we had a failing test case in Gecko. 😄 (Though my code comment mentions an example that I don't see in the spec, even in version 1.1.) 🤷‍♀️

That said, if an author put a table element inside a label element and provided no other name source, I would think that the displayed text should be the accessible name of the thing being labelled.

And that said, I don't have a strong opinion on this.

@spectranaut
Copy link
Contributor

Discussed in today's meeting: https://www.w3.org/2024/02/01-aria-minutes.html#t06

@scottaohara
Copy link
Member

the worry that I have with the 'never traverse' list, as i understand it, is that this wouldn't solve the recurring problem that keeps coming up with valid html (note: valid html doesn't mean it's necessarily 'good') :

<a href=>
  <article>
     <h2>foo</h2>
      other stuff goes here
  </article>
</a>

in that example the link has no name because the article has no name, even though the article has content that could be used as the name. It seems to me that for scenarios like this, if an element (which honestly might be limited to hyperlinks - this is where the problem keeps coming up) runs into an element like article and gets no name from it, it shouldn't stop there and not traverse into the article to get something useful.

However, if the article was given a name, then i think it's fair for the name computation to stop there and not grab all the content of the article to create it's accessible name.

cc @jcsteh for your thoughts and to correct me if i misunderstood what you were suggesting

@jcsteh
Copy link

jcsteh commented Feb 1, 2024

in that example the link has no name because the article has no name, even though the article has content that could be used as the name. It seems to me that for scenarios like this, if an element (which honestly might be limited to hyperlinks - this is where the problem keeps coming up) runs into an element like article and gets no name from it, it shouldn't stop there and not traverse into the article to get something useful.

So on one hand, I grant that it's really not ideal to have no name for something that occurs in the wild. On the other hand, you could probably find examples of all sorts of inaccessible behaviour in the wild that are considered "valid HTML". In addition, we do not want to encourage this behaviour. Maybe this is a case where we need to make article-in-link part of the repair behaviour, but not considered "valid" from an a11y perspective. That is, I absolutely want a11y validators to flag this as bad behaviour.

When you see this pattern, how big is the "article"? I don't like the idea of an entire article (in the true sense of the word) being shoved into the label of a link.

However, if the article was given a name, then i think it's fair for the name computation to stop there and not grab all the content of the article to create it's accessible name.

That already happens for everything in the "never traverse" list.

@accdc
Copy link
Contributor Author

accdc commented Feb 1, 2024

Unfortunately the problem with links is more broad, in that according to the HTML spec you can put anything within one. E.G a layout table, landmark region, list markup, and much else, all of which breaks this computation. Devs keep doing this because according to HTML there is nothing wrong with it according to validators.

As a possible workaround, would it be of benefit if we added an exception for link, where, if a name is not returned using the regular algorithm, it will attempt to traverse all children regardless of role to return any contained textual content as a failsafe?

@jcsteh
Copy link

jcsteh commented Feb 1, 2024

IMO, we still shouldn't consider this valid. It's a bad pattern, valid HTML or not, and it hurts users; it's hard to say whether an unnamed link or a link with a 500000 character label is worse. We can call it repair, fine, but IMO, it should still be flagged as invalid by a11y validators/checkers. But I'm one voice and I understand there is complexity here. I'm not going to push any further if the consensus is to make a "valid" exception for this case, as much as I might cringe about it. :)

@JAWS-test
Copy link
Contributor

@jcsteh: There may also be elements in the link that provide a very short AccName and should be valid, and yet do not work, i.e. links with blockquote or figure have no AccName. I think that "never traverse" should not occur for any element or role. I have nothing against setting a maximum AccName length and then simply truncating the text afterwards

@jcsteh
Copy link

jcsteh commented Feb 2, 2024

At that point, we're just always traversing everything. Are you suggesting that it's reasonable to traverse a listbox if it happens to be a descendant of a name from: contents target? Consider:

data:text/html,<div role="table"><div role="row"><div role="cell"><select size="2"><option>a</option><option>b</option><option>... several thousand more options ...</option></select></div></div></div>

I don't think it's at all reasonable for the cell to have the name "a b ... several thousand more options ..."

@JAWS-test
Copy link
Contributor

@jcsteh No, because of AccName 2 E:

If the embedded control has role combobox or listbox, return the text alternative of the chosen option.

@jcsteh
Copy link

jcsteh commented Feb 2, 2024

Fair enough; I forgot listbox was covered by that rule. What if it were role="tree" with 10000 treeitems?

@accdc
Copy link
Contributor Author

accdc commented Feb 2, 2024

In the case of role=tree the same would be true, only the selected treeitem is valid as the returned option for the widget.

All of these are moot points though, since a selectable listbox or a tree should not be embedded in a link. We shouldn't be endorsing embedded widgets within active elements.

If we do allow full traversal within a link, it should only apply to static container elements that are not interactive widgets with selectable options.

@MarioBatusic
Copy link
Contributor

@scottaohara I tested you example (extended and with or without aria-label on the link with Chrome and JAWS / NVDA. The more dangerous situation is, when a dev puts an aria-label on such a link: in this case he/she hides all the content of the article from screen reader user. Without an aria-label it would be quite OK, if screen readers would optimize their link handling - e.g. only saying link start on the beginning and link end on the end of the whole contents. At the time NVDA shows in Braille and reads the content well with all the set structure. JAWS puts all paragraphs of text in Braille on one line - I find it ungly.

@scottaohara
Copy link
Member

scottaohara commented Feb 8, 2024

yes, screen readers can handle this differently though, and do seem to be working around that the hyperlink has no name, but they are exposing something anyway. Which... unfortunately, is not something I believe we can consistently bank on always working.

@cookiecrook
Copy link
Contributor

For future Deep Dive planning, please include @twilco and me.

@cookiecrook
Copy link
Contributor

Assigning @scottaohara who graciously agreed to write up a summary and change suggestion.

@spectranaut
Copy link
Contributor

As @cookiecrook just wrote above, we briefly discussed this in the ARIA working group last week: https://www.w3.org/2024/02/08-aria-minutes#t04

After @cookiecrook and @scottaohara write up a summary, I'll schedule a deep dive.

@scottaohara
Copy link
Member

Summary:
At a super high level, the summary of this issue comes down to the fact that there are certain elements/roles which can compute their accessible name from their contents - but there are other elements/roles which do not allow the naming algorithm to traverse them, thus preventing available text content from being used in calculating the higher-level ancestor element's accessible name.

This is both something that is necessary to maintain, but has caused some issues to arise - particularly do to hyperlinks, as in HTML hyperlinks have a transparent content model. What this means is that a hyperlink can wrap an element/role that doesnt' allow for the accName algorithm to traverse its contents.  Hence hyperlinks can return as having no name if their only immediate child elemnet is something like an unnamed article, figure, table, aside, etc. - each of these elements only receiving their name if one has been explicitly provided by an author.

When this issue was discussed in the past, this did result in instances of hyperlinks (this issue really mostly occurs becaues of hyperlinks, i can't think of another instance where this is actually an issue / isn't also an author validation error) returning no names when accessed by AT.  However, recent testing shows that even though some browsers, such as Chromium-based browers, indicate that such hyperlinks have no name in their accessibility tree, browsers and/or AT are clearly working around this, and can still expose this unmamed link's content.

Proposal:

Note that innertext may be used by AT to compute a name for an element which otherwise the browser has returned no name for.

By noting this allowance, it both helps acknowledge what some browsers and screen readers are already doing.  E.g., Chromium returns an empty accessible name for the hyperlink that contains an unnamed article example, but JAWS and NVDA still expose the content of the hyperlink anyway.

If we do this rather than making a normative change to accName, then we do not run the risks of ballooning performance for these potentially recursive name calculations, nor do we potentially change/break current behavior that people (users and AT developers) might be currently relying on.

Additionally, by adding this note to the spec, we can resolve this issue as - at least presently - a 'wont fix', and mitigate future issues from being logged where we have to refer back to unresolved github threads to figure out what we had previously discussed, decided, but did not officially resolve on.

@jcsteh
Copy link

jcsteh commented Feb 15, 2024

Thanks for the summary. I think there's an additional concern here, though, which is that the spec doesn't specify which elements can be recursively traversed, even where they don't permit name from content. For example, unless I'm missing something, it's not clear that the button in the following example should have the label "test", rather than having an empty name:

data:text/html,<button><sub>test</sub></button>

The sub element prohibits a name and thus has no name, which is fine. However, because it doesn't allow name from content, the spec says we shouldn't traverse inside it. On the contrary, we must traverse inside it because we're calculating the name for the button, not the sub.

@aleventhal
Copy link
Contributor

aleventhal commented Feb 22, 2024

@jcsteh I think in the sub case, at least for Chrome, we just count that as "can contribute to ancestor names", whereas article is, dont use for either the ancestor or self case. Anyway, what do you propose so that we move forward with something?

@scottaohara at first I thought you meant a UA repair, via element.innerText, but now I realize you mean it's an AT repair. Just a point of clarification. The "inner text" may not mean exactly the same thing to everyone, e.g. does it include alt text.

@scottaohara scottaohara assigned accdc and unassigned scottaohara Feb 22, 2024
@cyns
Copy link
Contributor

cyns commented Feb 22, 2024

@aleventhal is "can contribute to ancestor names" defined anywhere? Could we put that definition in the spec and use it as the basis to specify which elements can be traversed recursively as @jcsteh suggests?

@accdc
Copy link
Contributor Author

accdc commented Feb 22, 2024

We discussed this today in the ARIA meeting, and we still don't have agreement. I'll try to summarize my thoughts.

I believe button is not really an issue and should stay as is. Button, unlike link, is children presentational, so it always flattens whatever is in it and I don't believe it ever takes into account what roles are included because of this. Whatever change we decide, I think limiting it to link would be the safest option.

I personally don't mind Scott's proposal as a last ditch fallback when nothing is returned for the name of a link, to use the inner textual content instead, even though this feels hacky from an algorithm perspective.

Stepping back for a moment, the only place this issue really occurs is when traversing the contents of a link, and only when an element is encountered that does not support name from content.

With this in mind, what do you think of the following logic when traversing the children of a link?

If the ancestor element of the current node is a link,
and the current node does not include an explicit name from author,
and the current node does not support name from content,
then continue traversing the child nodes of the current node regardless.

It seems to me that this would address the parsing of embedded constructs like tables, lists, figures, and all other static elements that don't support name from content while also honoring an actual label if an author deliberately sets one.

@aleventhal
Copy link
Contributor

aleventhal commented Feb 22, 2024 via email

@jcsteh
Copy link

jcsteh commented Feb 23, 2024

I don't think it's ever been defined, it's just something that browsers do.

All I'm suggesting is that we formalise that in the spec, which I understood to be one of the goals of this proposal in the first place and what my lists above attempt to do.

@spectranaut
Copy link
Contributor

Minutes from last weeks meeting: https://www.w3.org/2024/02/22-aria-minutes#t05

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests