-
Notifications
You must be signed in to change notification settings - Fork 24.4k
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
[a11y] Accessibility for nested text components #32004
Comments
There is no easy solution for this, even if try to create empty, pressable Views just where the pressable link is (using absolute positioning). This is because, onTextLayout/onLayout does not fire for the nested Text elements and hence it is not possible to know their position. |
@amarlette, that's a big issue for consumers of our library https://github.com/meliorence/react-native-render-html, do you think this issue could be addressed in the context of the GAAD Pledge? |
Possible duplicate of #31298 |
@jsamr Do you have any related issue threads from |
@tj-mc At least one, yes! meliorence/react-native-render-html#285 |
Thanks. I'm doing my best to understand what technical solution would be required here, and if it's within my reach, as I also feel this is an important issue. I agree @jsamr that this is a duplicate of #31298. @frags51, Would we consider closing this issue, and continuing this conversation in #31298? |
as documented in my test case fabOnReact/react-native-notes#9 (comment) this was solved with commit b352e2d on Android
currently working on fabOnReact/react-native-notes#9 (comment). thanks |
Summary: This issue fixes [32004][23]. The Pull Request was previously published by [blavalla][10] with [31757][24]. >This is a follow-up on [D23553222 (https://github.com/facebook/react-native/commit/b352e2da8137452f66717cf1cecb2e72abd727d7)][18], which made links functional by using [Talkback's Links menu][1]. We don't often use this as the sole access point for links due to it being more difficult for users to navigate to and easy for users to miss if they don't listen to the full description, including the hint text that announces that links are available. The Implementation of the functionality consists of: Retrieving the accessibility links and triggering the TalkBack Focus over the Text 1. nested Text components with accessibilityRole link are saved as [ReactClickableSpan][17] instances in Android native [TextView][20] ([more info][19]) 1. If the TextView contains any [ClickableSpans][15] (which are [nested Text][14] components with role link), set a view tag and reset the accessibility delegate. 3. Obtain each link description, start, end, and position relative to the parent Text (id) from the Span as an [AccessibilityLink][16] 4. Use the [AccessibilityLink][16] to display TalkBack focus over the link with the `getVirtualViewAt` method (more [info][13]) Implementing ExploreByTouchHelper to detect touches over links and to display TalkBack rectangle around them. 1. ReactAccessibilityDelegate inherits from [ExploreByTouchHelper][12] 2. If the [ReactTextView][21] has an accessibility delegate, trigger ExploreByTouchHelper method [dispatchHoverEvent][22] 3. Implements the methods `getVirtualViewAt` and `onPopulateBoundsForVirtualView`. The two methods implements the following functionalities (more [info][13]): * detecting the TalkBack onPress/focus on nested Text with accessibilityRole="link" * displaying TalkBack rectangle around nested Text with accessibilityRole="link" ## Changelog [Android] [Added] - Make links independently focusable by Talkback Pull Request resolved: #33215 Test Plan: [1]. User Interacts with links through TalkBack default accessibility menu ([link][1]) [2]. The nested link becomes the next focusable element after the parent element that contains it. ([link][2]) [3]. Testing accessibility examples in pr branch ([link][3]) [4]. Testing accessibility android examples in pr branch ([link][4]) [7]. TalkBack focus moves through links in the correct order from top to bottom (PR Branch with [link.id][25]) ([link to video test][7]) ([discussion][26]) [8]. TalkBack focus does not move through links in the correct order from top to bottom (PR Branch without [link.id][25]) ([link to video test][8]) ([discussion][26]) Test on main branch [5]. Testing accessibility examples in main branch ([link][5]) [6]. Testing accessibility android examples in main branch ([link][6]) [1]: fabOnReact/react-native-notes#9 (comment) [2]: fabOnReact/react-native-notes#9 (comment) [3]: fabOnReact/react-native-notes#9 (comment) [4]: fabOnReact/react-native-notes#9 (comment) [5]: fabOnReact/react-native-notes#9 (comment) [6]: fabOnReact/react-native-notes#9 (comment) [7]: fabOnReact/react-native-notes#9 (comment) [8]: fabOnReact/react-native-notes#9 (comment) [10]: https://github.com/blavalla "blavalla github profile" [12]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/com/android/internal/widget/ExploreByTouchHelper.java#L48 "com/android/internal/widget/ExploreByTouchHelper.java#L48" [13]: fabOnReact/react-native-notes#9 (comment) "explanation of getVirtualViewAt and onPopulateBoundsForVirtualView" [14]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/android/text/Spannable.java#L3 "core/java/android/text/Spannable.java#L3" [15]: https://github.com/fabriziobertoglio1987/react-native/blob/561266fc180b96d6337d6c6c5c3323522d66cc44/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java#L70-L71 "react/views/text/ReactTextViewManager.java#L70-L71" [16]: https://github.com/fabriziobertoglio1987/react-native/blob/561266fc180b96d6337d6c6c5c3323522d66cc44/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java#L680-L685 "react/uimanager/ReactAccessibilityDelegate.java#L680-L685" [17]: https://github.com/facebook/react-native/blob/561266fc180b96d6337d6c6c5c3323522d66cc44/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java#L126-L129 "react/views/text/TextLayoutManager.java#L126-L129" [18]: b352e2d [19]: #30375 (comment) "explanation on how nested Text are converted to Android Spans" [20]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/android/widget/TextView.java#L214-L220 "core/java/android/widget/TextView.java#L214-L220" [21]: https://github.com/facebook/react-native/blob/485cf6118b0ab0b59e078b96701b69ae64c4dfb7/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java#L577 "dispatchHoverEvent in ReactTextView" [22]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/com/android/internal/widget/ExploreByTouchHelper.java#L120-L138 "dispatchHoverEvent in ExploreByTouchHelper" [23]: #32004 [24]: #31757 [25]: https://github.com/fabriziobertoglio1987/react-native/blob/485cf6118b0ab0b59e078b96701b69ae64c4dfb7/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java#L648 "setting link.id in the AccessibilityLink constructor" [26]: https://github.com/facebook/react-native/pull/33215/files/485cf6118b0ab0b59e078b96701b69ae64c4dfb7#r820014411 "comment on role of link.id" Reviewed By: blavalla Differential Revision: D34687371 Pulled By: philIip fbshipit-source-id: 8e63c70e9318ad8d27317bd68497705e595dea0f
@frags51 , has this been resolved by @fabriziobertoglio1987 's PR? |
@fabriziobertoglio1987 Is this working on iOS as well? @blavalla if not, then it needs to be solved for iOS too. |
Is there at least an iOS workaround? I'm experiencing this now |
Thanks for addressing this on Android, @fabriziobertoglio1987. This is not working on iOS currently, and it would be great to have a fix for that as well, thanks. |
Why wouldn't you just wrap the text in a Touchable? Semantically, this is more accurate I think. |
I tested the following scenarios:
The functionality works on the main branch. I remain available. Thanks Testing iOS nested text without accessibilityRole link VID_20221219_153333.mp4Related Links:
|
Summary: This issue fixes [32004][23]. The Pull Request was previously published by [blavalla][10] with [31757][24]. >This is a follow-up on [D23553222 (https://github.com/facebook/react-native/commit/b352e2da8137452f66717cf1cecb2e72abd727d7)][18], which made links functional by using [Talkback's Links menu][1]. We don't often use this as the sole access point for links due to it being more difficult for users to navigate to and easy for users to miss if they don't listen to the full description, including the hint text that announces that links are available. The Implementation of the functionality consists of: Retrieving the accessibility links and triggering the TalkBack Focus over the Text 1. nested Text components with accessibilityRole link are saved as [ReactClickableSpan][17] instances in Android native [TextView][20] ([more info][19]) 1. If the TextView contains any [ClickableSpans][15] (which are [nested Text][14] components with role link), set a view tag and reset the accessibility delegate. 3. Obtain each link description, start, end, and position relative to the parent Text (id) from the Span as an [AccessibilityLink][16] 4. Use the [AccessibilityLink][16] to display TalkBack focus over the link with the `getVirtualViewAt` method (more [info][13]) Implementing ExploreByTouchHelper to detect touches over links and to display TalkBack rectangle around them. 1. ReactAccessibilityDelegate inherits from [ExploreByTouchHelper][12] 2. If the [ReactTextView][21] has an accessibility delegate, trigger ExploreByTouchHelper method [dispatchHoverEvent][22] 3. Implements the methods `getVirtualViewAt` and `onPopulateBoundsForVirtualView`. The two methods implements the following functionalities (more [info][13]): * detecting the TalkBack onPress/focus on nested Text with accessibilityRole="link" * displaying TalkBack rectangle around nested Text with accessibilityRole="link" ## Changelog [Android] [Added] - Make links independently focusable by Talkback Pull Request resolved: facebook#33215 Test Plan: [1]. User Interacts with links through TalkBack default accessibility menu ([link][1]) [2]. The nested link becomes the next focusable element after the parent element that contains it. ([link][2]) [3]. Testing accessibility examples in pr branch ([link][3]) [4]. Testing accessibility android examples in pr branch ([link][4]) [7]. TalkBack focus moves through links in the correct order from top to bottom (PR Branch with [link.id][25]) ([link to video test][7]) ([discussion][26]) [8]. TalkBack focus does not move through links in the correct order from top to bottom (PR Branch without [link.id][25]) ([link to video test][8]) ([discussion][26]) Test on main branch [5]. Testing accessibility examples in main branch ([link][5]) [6]. Testing accessibility android examples in main branch ([link][6]) [1]: fabOnReact/react-native-notes#9 (comment) [2]: fabOnReact/react-native-notes#9 (comment) [3]: fabOnReact/react-native-notes#9 (comment) [4]: fabOnReact/react-native-notes#9 (comment) [5]: fabOnReact/react-native-notes#9 (comment) [6]: fabOnReact/react-native-notes#9 (comment) [7]: fabOnReact/react-native-notes#9 (comment) [8]: fabOnReact/react-native-notes#9 (comment) [10]: https://github.com/blavalla "blavalla github profile" [12]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/com/android/internal/widget/ExploreByTouchHelper.java#L48 "com/android/internal/widget/ExploreByTouchHelper.java#L48" [13]: fabOnReact/react-native-notes#9 (comment) "explanation of getVirtualViewAt and onPopulateBoundsForVirtualView" [14]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/android/text/Spannable.java#L3 "core/java/android/text/Spannable.java#L3" [15]: https://github.com/fabriziobertoglio1987/react-native/blob/561266fc180b96d6337d6c6c5c3323522d66cc44/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java#L70-L71 "react/views/text/ReactTextViewManager.java#L70-L71" [16]: https://github.com/fabriziobertoglio1987/react-native/blob/561266fc180b96d6337d6c6c5c3323522d66cc44/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java#L680-L685 "react/uimanager/ReactAccessibilityDelegate.java#L680-L685" [17]: https://github.com/facebook/react-native/blob/561266fc180b96d6337d6c6c5c3323522d66cc44/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java#L126-L129 "react/views/text/TextLayoutManager.java#L126-L129" [18]: facebook@b352e2d [19]: facebook#30375 (comment) "explanation on how nested Text are converted to Android Spans" [20]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/android/widget/TextView.java#L214-L220 "core/java/android/widget/TextView.java#L214-L220" [21]: https://github.com/facebook/react-native/blob/485cf6118b0ab0b59e078b96701b69ae64c4dfb7/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java#L577 "dispatchHoverEvent in ReactTextView" [22]: https://github.com/aosp-mirror/platform_frameworks_base/blob/1ac46f932ef88a8f96d652580d8105e361ffc842/core/java/com/android/internal/widget/ExploreByTouchHelper.java#L120-L138 "dispatchHoverEvent in ExploreByTouchHelper" [23]: facebook#32004 [24]: facebook#31757 [25]: https://github.com/fabriziobertoglio1987/react-native/blob/485cf6118b0ab0b59e078b96701b69ae64c4dfb7/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactAccessibilityDelegate.java#L648 "setting link.id in the AccessibilityLink constructor" [26]: https://github.com/facebook/react-native/pull/33215/files/485cf6118b0ab0b59e078b96701b69ae64c4dfb7#r820014411 "comment on role of link.id" Reviewed By: blavalla Differential Revision: D34687371 Pulled By: philIip fbshipit-source-id: 8e63c70e9318ad8d27317bd68497705e595dea0f
We're considering using this approach for handling inline links on iOS: https://benjie.ca/blog/2021/09/21/accessible-inline-links-react-native.html It's not perfect, but at least makes the links available to VoiceOver users. An alternative approach might be to use an accessibility action. |
De bron van het probleem is een bug / missende feature in RN: [FAQ in `react-native-render-html`](https://meliorence.github.io/react-native-render-html/docs/faq#some-anchors-a-are-not-accessible-to-screen-readers). Ik begrijp op zich wel dat het focussen op of voorlezen van een link in een alinea wat complexiteit geeft om te implementeren. Focus: tik je op de alinea of de link? Voorlezen: hoe geef je aan dat de ‘link’ rol alleen op die link van toepassing is? Het idee van de oplossingen (of liever workarounds) die ik tegenkom, is dat de HTML gesplitst wordt in losse tekstcomponenten, zodat hun rol individueel voorgelezen kan worden en ze individueel te focusen zijn. Qua voorlezen is dat niet ideaal, omdat er pauzes midden in een zin komen. Ook qua weergave niet, omdat je normaal gesproken witregels krijgt tenzij je die weer wegwerkt. Als we het voorlezen mikken op niet-ziende mensen is dat laatste geen probleem. En in elk geval beter dan de huidige situatie waarin de link helemaal niet te vinden is. Voor deze eerste, POC-achtige implementatie probeer ik HTML te splitsen in paragrafen met en zonder links. Alternatief zou misschien een custom renderer zijn. Ik weet nog niet of we eerst moeten mikken op de korte fragmentjes HTML die we in de afvalwijzer tegenkomen of ook al moeten rekening houden met inline links in bijv. de Werkzaamheden-proza. Ook vraag ik me af of het qua performance acceptabel is om dit steeds te splitsen, al hoeven we het alleen te doen als we zien dat een schermlezer (of toetsenbord?) actief is. Ik heb alvast een hook `isScreenReaderEnabled` toegevoegd, kopie van `isReduceMotionEnabled`. Doet het nog niet, waarschijnlijk omdat ik nog niet helemaal door heb of dit nu op het juiste moment geëvalueerd wordt. Ook betwijfel ik of die `callbackAfterAppStateChange` wel meegenomen moet worden. Referenties: * facebook/react-native#32004 * https://www.callstack.com/blog/react-native-android-accessibility-tips (wordt ook gelinkt in die FAQ hierboven) * https://benjie.ca/blog/2021/09/21/accessible-inline-links-react-native.html Related work items: #81491
I have the same problem!
In my case, I have 2 nested links. On Android, the screen reader recognize the links, but on iOS it doesn't |
Has anyone found a solution for this that works for more than one link in a paragraph? I am building a news app for a major publication. We must meet WCAG AA, which I believe all apps should aim for, and I am struggling to find a path forward. This issue has been literally keeping me up at night. We don't have the time or resources at this stage in the project to upgrade to the new architecture, which seems risky anyways, given that Expo only just now released experimental support (we're on Expo), and a quick spike I did that uncovered some bugs we'd have to resolve. I'm shocked that React Native has such a fundamental accessibility gap here and that there hasn't been an effort to port the fix to the old architecture. |
I agree this is an unfortunate gap. Is it solved in the new architecture? Perhaps if you have rich text content, an inline webview might be a better solution. You can load local HTML and render without a loading time if it's static. It seems like most news apps I use are native wrappers around web layouts. |
Thanks for this suggestion, @tj-mc! I converted this portion of my app to use webviews instead, and this completely solved my accessibility issues. Screen reader, voice control, keyboard all work exactly as expected. It's a shame that we have to use webviews as an escape hatch, and I certainly wouldn't consider this issue as solved because of that option, but I am glad to have found a way to move forward. |
@stevehanson The changes shown in this PR could be a workaround. Webview/HTML definitely helps but do consider the perf/memory implications of using one. |
Hi team, Any update on this issue? |
After testing with Accessibility Inspector on iOS Simulator and TalkBack on the Android emulator, my conclusion is that this does appear to be adequately solved on the new architecture on iOS and with TalkBack on the old renderer, but is not solved on the old renderer on iOS, as also noted in #35193. In the old architecture on iOS, VoiceOver reads the content of the link, but it is not possible to independently select it with VoiceOver or open the link using VoiceOver alone. This could vary on actual devices, but that's what I'm seeing in the simulator. I realize this amounts to a summary of what others have concluded above, but I was confused reading through the comments on this issue and wanted to confirm whether it had been addressed and the scope. |
@chriszs, The role of link must be announced to user as if it does not announce the role user who depends on Voiceover will be impacted , Also Voice over is announcing it as Static text with no other information like double tap to activate the link. |
@msftedad Good point. Do you think that works okay on the new architecture and Android (where Android offers to provide a list of links after the paragraph has been read)? |
Hi @chriszs, This was discussed and as per the Inputs, this will be read on Android as well, so user will be aware of the information in paragraph. |
@chriszs , Any update? |
I faced the same issue, if I put Text inside Text with accessibility role "link" and onPress, on the Android emulator it says that link can be opened using swipe up then swipe right, but on iOS it does not recognise as it is link
|
Description
Same as (stale) #27147.
Consider this example:
A screen reader user is not able to click/open the link (i.e. the 2nd nested Text component). Ideally, the screen reader should focus on the link as well. The addition of any permutation of accessibility props on the parent/child Text component does not help.
React Native version:
React native 0.62.
React Native Environment Info:
System:
OS: Windows 10
CPU: (12) x64 AMD Ryzen 5 5600X 6-Core Processor
Memory: 19.72 GB / 31.92 GB
Binaries:
Node: 12.21.0 - C:\Users\supsing\AppData\Local\Temp\yarn--1628676998345-0.3639484914346074\node.CMD
Yarn: 1.22.10 - C:\Users\supsing\AppData\Local\Temp\yarn--1628676998345-0.3639484914346074\yarn.CMD
npm: 6.14.11 - C:\Users\supsing\AppData\Local\nvs\default\npm.CMD
Watchman: 20210102.202219.0 - E:\watchman-v2021.01.04.00-windows\bin\watchman.EXE
Steps To Reproduce
Write nested text components as shown in the description.
Expected Results
Screen reader (Voiceover/talkback) should be able to tell the user that there is a link and user should be able to click on that link.
In Android (native), talkback adds any links available in a single text view in the accessibility menu (can be opened using swipe up then swipe right). The same should be done by React Native as well. Perhaps it can be achieved with ClickableSpan in Android. There should be similar ways in iOS as well.
Snack, code example, screenshot, or link to a repository:
The text was updated successfully, but these errors were encountered: