Bug 223492

Summary: AX: [iOS] [Voice Over] Voice Over skips elements with role="group" and role="region"
Product: WebKit Reporter: alehm
Component: AccessibilityAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Major CC: cfleizach, mijordan, tyler_w, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Safari 14   
Hardware: iPhone / iPad   
OS: iOS 14   

Description alehm 2021-03-18 18:21:53 PDT
Hi,

Google Maps JS API team is blocked by this bug.

Please consider the following demo: https://codesandbox.io/s/headless-sunset-7fted.

There are 2 `div` elements with `tabindex`, `role` and `aria-label` attributes defined. Voice Over on iOS devices (Safari and Chrome) skips these elements and navigates to child elements (either focusable or non-focusable) when using gestures (swipe left and right) to navigate through elements on a page.

We use `role="group"` attribute. W3 says that `group (role)` attribute is "a set of user interface objects which are not intended to be included in a page summary or table of contents by assistive technologies.", so we tried `role="region"` attribute and according to W3 "Assistive technologies *SHOULD* enable users to quickly navigate to elements with role region".

Please note, that Voice Over on MacOS devices does recognize elements with `role="region"` and `role="group"` when navigating using Tab/Shift-Tab and VO + Left arrow/VO + Right arrow keys.

Please let us know if more details are needed.
Comment 1 Radar WebKit Bug Importer 2021-03-18 18:22:03 PDT
<rdar://problem/75600822>
Comment 2 chris fleizach 2021-03-19 09:54:53 PDT
Hi, on iOS VoiceOver only lands on "leaf nodes". If a group parent has a description, often times that will description will be included in the description when you land within that region.

So to make these have VO land on it, they need to have a role of something that's like a leaf node. 

For example for a map, I would expect VO would be able to land on objets within a map. but the first time landing on that road or POI within a map, it would append "map" as it moved into that area

Feel free to email me if we need to have a more detailed discussion
Comment 3 alehm 2021-03-19 17:13:16 PDT
Hi Chris,

Thanks you so much for your prompt response and provided details!

I'm wondering if there any plans for VO on iOS still to land on an element with role="group" or role="region". 

In our case this element (with role="group") is focusable (has tabindex="0" attribute defined) where keyboard and gesture handling interactions can be applied. Skipping this element with VO enabled seems to be a blocker for us.
Comment 4 chris fleizach 2021-03-19 17:18:18 PDT
(In reply to alehm from comment #3)
> Hi Chris,
> 
> Thanks you so much for your prompt response and provided details!
> 
> I'm wondering if there any plans for VO on iOS still to land on an element
> with role="group" or role="region". 
> 
> In our case this element (with role="group") is focusable (has tabindex="0"
> attribute defined) where keyboard and gesture handling interactions can be
> applied. Skipping this element with VO enabled seems to be a blocker for us.

Does VO land on the object inside the group in this case? Is that not sufficient in this case?
Comment 5 alehm 2021-03-19 17:25:49 PDT
It does land on objects inside the group, however a "Map" word is not appended. Another case is that objects inside the group are not always present in the DOM (depends on actual usage of Google Maps JS API), but the group element itself is still keyboard-interactive.
Comment 6 chris fleizach 2021-03-19 17:34:02 PDT
(In reply to alehm from comment #5)
> It does land on objects inside the group, however a "Map" word is not
> appended. Another case is that objects inside the group are not always
> present in the DOM (depends on actual usage of Google Maps JS API), but the
> group element itself is still keyboard-interactive.

1) I consider it a bug that we don’t add that custom role description. We can address that

2) can you explain more about object inside the group not being in the DOM? Is the element that it lands on something you don’t want it to land on? If there were no children, and we saw a group head keyboard focusable, I could see the case that we’d want to land on it in that case
Comment 7 alehm 2021-03-19 17:41:54 PDT
1) Thanks!

2) Sorry, I should've been more precise. Objects (POIs) are not always created by developers who use our API and therefore our group element doesn't always have focusable objects inside it. There are, however, other non-focusable `div` elements inside the group element which are used as separate layers which may or may not contain focusable elements (objects).
Comment 8 chris fleizach 2021-03-19 17:50:49 PDT
(In reply to alehm from comment #7)
> 1) Thanks!
> 
> 2) Sorry, I should've been more precise. Objects (POIs) are not always
> created by developers who use our API and therefore our group element
> doesn't always have focusable objects inside it. There are, however, other
> non-focusable `div` elements inside the group element which are used as
> separate layers which may or may not contain focusable elements (objects).

These would not be accessible to VO unless they were tagged as some useful role though right? The experience on iOS is meant to be to land on things inside the group rather than landing on the group first,unless there are no accessible elements, in which case landing on the group is acceptable to allow access to something. So in summary, I feel like if we fix #1 then this will behave as expected.
Comment 9 alehm 2021-03-19 17:59:04 PDT
Correct, we tend to add appropriate roles to objects placed inside the group to make them accessible and screen reader friendly. However, if there are no accessible elements (e.g. POIs) inside the group we still want VO to stop there because a map without POIs in it is still worth explaining to the user (it’s a form of imagery, almost like an <img>)
Comment 10 chris fleizach 2021-03-19 18:04:11 PDT
(In reply to alehm from comment #9)
> Correct, we tend to add appropriate roles to objects placed inside the group
> to make them accessible and screen reader friendly. However, if there are no
> accessible elements (e.g. POIs) inside the group we still want VO to stop
> there because a map without POIs in it is still worth explaining to the user
> (it’s a form of imagery, almost like an <img>)

Ok seems reasonable. If a keyboard focusable item has no children it should still be accessible.
Comment 11 alehm 2021-10-19 11:52:51 PDT
Hi, 

We would really appreciate it if you could provide any updates on this bug. Is there any timeline of when this might be fixed/addressed?

Usage of Maps JS is pretty high across the globe and thus a lot of users might already be affected.

Sincerely,
Aleh
Comment 12 chris fleizach 2021-10-19 12:41:40 PDT
(In reply to alehm from comment #11)
> Hi, 
> 
> We would really appreciate it if you could provide any updates on this bug.
> Is there any timeline of when this might be fixed/addressed?
> 
> Usage of Maps JS is pretty high across the globe and thus a lot of users
> might already be affected.
> 
> Sincerely,
> Aleh

Yes, @TylerW will take a look at this soon
Comment 13 Tyler Wilcock 2021-10-19 12:42:50 PDT
Let me make sure I understand the issues here.

First, in this snippet from the codesandbox:

<div
    tabindex="0"
    role="group"
    aria-label="Map"
    aria-roledescription="map"
>
    <p>Some text content</p>
</div>

VoiceOver speaks only "Some text content", without including the custom roledescription. I can reproduce this, and agree it's not right. But:

1. This example also includes an aria-label that is not read. How do we expect this interaction to work? Is it expected that VoiceOver read "Some text content, map, Map"?

2. What about multiple levels of groups with labels? Should they all be rolled up into the final spoken thing at the leaf?

<div aria-label="Yellow" role="group">
  <div aria-label="Blue" role="group">
    <div aria-label="Orange" role="group">
       Some text content
    </div>
  </div>
</div>

What should this read? "Some text content, yellow, blue, orange"?

I think yes, but want to be clear. Chris, thoughts?

---

Regarding what I'm interpreting as a different issue:

> Correct, we tend to add appropriate roles to objects placed inside the group to make them accessible and screen reader friendly. However, if there are no accessible elements (e.g. POIs) inside the group we still want VO to stop there because a map without POIs in it is still worth explaining to the user (it’s a form of imagery, almost like an <img>)

> Ok seems reasonable. If a keyboard focusable item has no children it should still be accessible.

Can you please include minimal code snippet(s) demonstrating this problem?
Comment 14 chris fleizach 2021-10-19 12:44:19 PDT
(In reply to Tyler Wilcock from comment #13)
> Let me make sure I understand the issues here.
> 
> First, in this snippet from the codesandbox:
> 
> <div
>     tabindex="0"
>     role="group"
>     aria-label="Map"
>     aria-roledescription="map"
> >
>     <p>Some text content</p>
> </div>
> 
> VoiceOver speaks only "Some text content", without including the custom
> roledescription. I can reproduce this, and agree it's not right. But:
> 
> 1. This example also includes an aria-label that is not read. How do we
> expect this interaction to work? Is it expected that VoiceOver read "Some
> text content, map, Map"?
> 
> 2. What about multiple levels of groups with labels? Should they all be
> rolled up into the final spoken thing at the leaf?
> 
> <div aria-label="Yellow" role="group">
>   <div aria-label="Blue" role="group">
>     <div aria-label="Orange" role="group">
>        Some text content
>     </div>
>   </div>
> </div>
> 
> What should this read? "Some text content, yellow, blue, orange"?
> 
> I think yes, but want to be clear. Chris, thoughts?
> 
> ---
> 
> Regarding what I'm interpreting as a different issue:
> 
> > Correct, we tend to add appropriate roles to objects placed inside the group to make them accessible and screen reader friendly. However, if there are no accessible elements (e.g. POIs) inside the group we still want VO to stop there because a map without POIs in it is still worth explaining to the user (it’s a form of imagery, almost like an <img>)
> 
> > Ok seems reasonable. If a keyboard focusable item has no children it should still be accessible.
> 
> Can you please include minimal code snippet(s) demonstrating this problem?

In my mind it was

<div role="group" tabindex="0" aria-label="blah"></div>

is a navigable element on iOS
Comment 15 Tyler Wilcock 2021-10-19 12:53:11 PDT
> In my mind it was
>   <div role="group" tabindex="0" aria-label="blah"></div>
> is a navigable element on iOS
OK, makes sense to me.
Comment 16 Tyler Wilcock 2021-10-25 15:42:50 PDT
https://bugs.webkit.org/show_bug.cgi?id=232126 addresses:

> Correct, we tend to add appropriate roles to objects placed inside the group
> to make them accessible and screen reader friendly. However, if there are no
> accessible elements (e.g. POIs) inside the group we still want VO to stop
> there because a map without POIs in it is still worth explaining to the user
> (it’s a form of imagery, almost like an <img>)
But currently only for things that have a height and width > 1px. Does this work for your usecase? I'm guessing so, as you describe these things as imagery, meaning they visually have some height and width?

An example in the form of HTML and a screenshot of one of these empty groups would be really helpful (if there's anything to see).
Comment 17 Tyler Wilcock 2021-10-25 15:48:22 PDT
Sorry, >= 1px.
Comment 18 alehm 2021-12-01 11:49:45 PST
I'm so sorry. I completely missed that. Yeah, our keyboard-focusable leaf nodes will be >= 1px. Thanks!

One more question: Will https://bugs.webkit.org/show_bug.cgi?id=232126 also fix #1 from https://bugs.webkit.org/show_bug.cgi?id=223492#c6 ?
Comment 19 Tyler Wilcock 2021-12-01 12:17:58 PST
(In reply to alehm from comment #18)
> One more question: Will https://bugs.webkit.org/show_bug.cgi?id=232126 also
> fix #1 from https://bugs.webkit.org/show_bug.cgi?id=223492#c6 ?
No, it won't. I had a fix for that piece, but I need to re-work it, as it would cause VoiceOver to repeat the same container labels over and over when iterating over sibling elements inside the container. It's on my radar to get back to.
Comment 20 alehm 2022-02-01 16:34:28 PST
Hi, Could you please let me know whether there are any updates or not?
Comment 21 Tyler Wilcock 2022-02-01 18:33:43 PST
Really sorry, but no further progress has been made on this yet.
Comment 22 Michael Jordan 2023-06-26 09:49:07 PDT
I'm not sure that a div[role="group"][tabindex][aria-roledescription] wrapping a <p> element containing static text is the best use case to illustrate the problem.

For additional context, that the accessible name for a [role="group"] of controls is not announced when an input control within the group receives focus with the VoiceOver cursor is a significant accessibility failure that affects many use cases, where, for what ever reason, developers choose [role="group"] over  fieldset and legend.

For example, a web component implementation of a two-handle slider could render using markup similar to the following:

<wc-slider label="Price Range" role="group" aria-label="Price Range">
  <span id="label">
    <label for="input-0" aria-hidden="true">Price Range</label>
    <output aria-live="off">$25 - $75</output>
  </span>
  <span id="handle-0" role="none">
    <input type="range" id="input-0" name="input-0" min="0" max="75" value="25" aria-valuetext="$25" aria-label="Minimum" />
  </span>
  <span id="handle-1" role="none">
    <input type="range" id="input-1" name="input-1" min="25" max="100" value="75" aria-valuetext="$75" aria-label="Maximum" />
  </span>
</wc-slider>

Swiping the VoiceOver cursor to focus the first input[type="range"] within the component should announce as "$25, Minimum, slider, Price Range, group." Swiping to the next input[type="range"] within the component should announce "$75, Maximum, slider," and swiping out of the component with role="group" to the next element should announce "End of Price Range, group."

Developers expect a role="group" with either aria-label or aria-labelledby to behave this way for their users, and the WAI even provides an example of a group of inputs for receiving a social security number, as part of its Techniques for WCAG 2.0. https://w3.org/TR/WCAG20-TECHS/ARIA17.html#ARIA17-ex1.

Here is a link to blog post lamenting that developers do not choose fieldset and legend instead of role="group", and providing a number of suggested workarounds for fieldset and legend layout issues, which in large part had to be written because of this ticket. https://adrianroselli.com/2022/07/use-legend-and-fieldset.html