software-mansion / software-mansion/react-native-screens
[Android] Accessibility: Keyboard focus cleared during navigation with native-stack
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 3.7k
- Forks
- 714
- Avg merge
- 2d 23h
- Merged PRs (30d)
- 71
Description
Description
I’m building an accessible audiobook app designed for blind users. Navigation is intentionally simple to match what they’re used to on PC, and I need to support not only iOS and Android touch devices, but also Android phones with hardware keypads (e.g. Qin F22 Pro, SmartVision 3) and Android TVs.
While testing with native-stack, I’ve run into several keyboard focus issues (it also have some of its own issues , i posted there too with a video):
- Focus cleared before navigating
When using native-stack, react-native-screens clears keyboard focus before navigation happens and talkback focus is all over because of it.
If I disable clearFocus() , the issue disappears (though I’m not sure what other side effects this might cause and slide_from_bottom still gets somehow bugged with talkback focus , slide_from_left , default and fade seems to work):
override fun clearFocus() {
if (visibility != INVISIBLE) {
// super.clearFocus()
}
}
With stack (non-native) navigation, I don’t have this problem, but then I can’t restore keyboard focus to the last item when going back.
- goBack / hardware back button clears focus too early
When calling navigation.goBack() (or pressing the hardware back button, which triggers it internally), the focus is cleared before the screen is removed.
This causes TalkBack to first focus on the disappearing screen, and then move focus to the destination screen, which is confusing for blind users.
I tested by delaying removeScreenAt:
override fun removeViewAt(parent: ScreenStack, index: Int) {
println("REMOVING SCREEN BEFORE ACTION")
val screen = parent.getScreenAt(index)
screen.postDelayed({
println("REMOVING SCREEN")
prepareOutTransition(screen)
parent.removeScreenAt(index)
NativeProxy.removeScreenFromMap(screen.id)
}, 5000)
}
I also tried the Android 13+ back dispatcher, which works correctly:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireActivity().onBackInvokedDispatcher.registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT
) {
dismissFromContainer()
}
}
Unfortunately, most of my target devices are still on Android 12, so I can’t rely on this.
- Modals / transparent modals
When using modals or transparent modals, keyboard focus incorrectly moves to the background screen, instead of staying within the modal.
I haven’t debugged this yet, but it currently makes modals unusable with a hardware keyboard.
I think its a timing issue.
Summary
react-native-screens clears keyboard focus too early when navigating, especially on goBack.
This causes major issues for screen reader and keyboard users on Android. (i have not tested on IOS)
Disabling clearFocus() works for navigating forward, but may have side effects.
The Android 13+ back dispatcher fixes the issue when going back, but older versions (common on keypad phones) are still affected.
Expected behavior:
Keyboard focus should remain stable across navigations.
Going back should restore focus to the previously focused element on the destination screen.
Modals should trap focus inside themselves.
Some type of animations have big problems with talkback , "fade" seem to play nice. (you can test with slide_from_bottom and talkback for example , with and without keyboard input)
Steps to reproduce
I already wrote in the description
Snack or a link to a repository
not needed
Screens version
4.13.1 and 4.14.0
React Native version
0.79 and 0.81
Platforms
Android
JavaScript runtime
Hermes
Workflow
Expo bare workflow
Architecture
None
Build type
None
Device
None
Device model
2 x Android 12 devices + emulators different versions
Acknowledgements
Yes
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the native-stack behavior on Android 12 with TalkBack and hardware-keyboard focus. Read the focus handling around clearFocus(), removeViewAt(), and removeScreenAt(), comparing it with the Android 13+ back dispatcher example. Done means focus remains stable during navigation, back navigation avoids focusing the disappearing screen, and modal focus stays within the modal.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin, react-native
- Domain
- accessibility, mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100