Effect of `accessible` prop on `*ByRole` + `hidden`, `inInaccessible`, etc
See original GitHub issueDescribe the issue
According to accessible
prop documentation, setting it to true
“groups its children into a single selectable component”. Then there is following example:
<View accessible={true}>
<Text>text one</Text>
<Text>text two</Text>
</View>
with following comment: “In the above example, we can’t get accessibility focus separately on ‘text one’ and ‘text two’. Instead we get focus on a parent view with ‘accessible’ property.”
I understand the above statement that there is no concept nested accessible elements. If you are able to “focus” on some element, then it is treated as a whole by accessibility APIs, you cannot “focus” on any of its descendants. In other words there “focusable” components form a linear structure (similar to tabIndex
attribute on Web) and not a tree structure when you could nest “focusable” element inside other “focusable” element.
We should consider including that behaviour in *ByRole
queries, and how does it affect other A11y related functions like upcoming hidden
query option #1064, isInaccessible
function, etc.
Some examples:
getByRole('button', { hidden: false })
should return only outerPressable
, becausePressable
renders hostView
withaccessible={true}
by default. InnerPressable
is not “focusable” because the outerPressable
forms a single focusable unit for assitive technology.
<Pressable accessibilityRole="button" testID="outer">
<Pressable accessibilityRole="button" testID="inner">
<Text>Press me</Text>
</Pressable>
</Pressable>
getByRole('button', { hidden: false })
should return only innerPressable
, because overridingaccessible
prop of outer pressable excludes it from reaching by assistive technology:
<Pressable accessibilityRole="button" testID="outer" accessible={false}>
<Pressable accessibilityRole="button" testID="inner">
<Text>Press me</Text>
</Pressable>
</Pressable>
In case of using hidden: true
option, aka respectAccessibility: false
, the above test cases would return both outer and inner Pressable
s.
Possible Implementations
We might modify isInaccessible
helper that will form the basis of exclusion for hidden
accessibility elements in #1064. That way descendants of element with accessible={true}
could be marked as inaccessible, while the element itself will be accessible.
This behaviour is related to upcoming hidden
option, with the default behaviour being initially hidden: true
aka respectAccessibility: false
, so that should not make a breaking change. In the longer term we plan change it to false
, as in RTL/DTL and only then this would be a breaking change.
Related Issues
@AugustinLF @thymikee @pierrezimmermannbam @MattAgn I’d would like to gather your feedback on proposed change, whether you see any potential issues,
Issue Analytics
- State:
- Created a year ago
- Comments:5 (2 by maintainers)
Top GitHub Comments
If I understand correctly, if this gets implemented with
hidden : true
, for the following component :This wouldn’t work anymore since the Text element is inaccessible
This means that we would systematically have to use byRole queries for pressing buttons by text (which if I’m correct requires to add the accessibilityRole prop for now). Even though it probably is a better way to do it and it seems interesting to enforce it, this would be a major breaking change and could be quite hard to fix on large codebases. However
hidden : false
could still be used in this kind of situation.What I’m more concerned about is that the behavior of queries becomes more and more complicated and unnatural to users, especially the ones that are not very familiar with how accessibility works. So while I think this goes in the right direction, this would need to be really well documented before being adopted. There should be a way to make this work, for instance with very good error messages and really good documentation but in any case making users understand what’s going on should be an important focus for this feature imo
Thanks for feedback. I share your concerns about affecting other queries, existing user tests, etc.
accessible prop effect on screen reader In order to learn some more about how the things really behave in RN, I’ve done some tests using iOS accessibility inspector and Android TalkBack and found that:
Based on these observations I think we should allow for searching inside elements with
accessibility={true}
despite the confusing docs. Let’s not involveaccessible
prop logic inisInaccessible
checks.fireEvent.press(getByText("Press me"))
should still work as is 😃DTL hidden option DTL only supports
hidden
option on*ByRole
queries, they do not have it for any other query(!). The reasoning behind this seems to be that only*ByRole
queries are a11y-aware, and other queries are lightweight. See here: https://github.com/testing-library/dom-testing-library/issues/929#issuecomment-817086144I think that in our case we would want to see
hidden
option on other queries, as one of the reasons we started to implement this option was to be able to search on only the active screen, assuming that all screens in the back stack, e.g. from React Navigation, have proper a11y props set.Potential usage for accessible prop What we might consider is matching only these elements with
*ByRole
query that are having explicitaccessible={true}
or behave as if they have it by default: e.g. hostText
andTextInput
behave in such way, hostView
does not. If we would pursue this way, it would be in order to match the observe RN behaviour. I’m not sure we do it at this stage though, as it warrants some more research in that context.If we went that way, then nested
Pressable
s with outer beingaccessible={false}
would not be matched bygetByRole("button", { name: "Pressable" })
. @AugustinLF iirc you had mentioned this case in some of the recent discussions regarding role queries.