Description
When a Stack-pushed screen is a child of <NativeTabs hidden={true}> (i.e. <Tabs.Host tabBarHidden={true}> on Android), any Pressable / TouchableOpacity rendered in the bottom ~56dp strip of the visible screen does not fire onPress on Android. The dead-zone width matches the BottomNavigationView's default height.
This affects both:
- Static layout — a
Pressable anchored to the bottom of the screen never fires.
- Scrollable content — a
Pressable inside a ScrollView / FlatList fires when scrolled above the strip, but stops firing the moment it scrolls into the bottom ~56dp. Scroll the same row a few pixels up and it works again. This proves the dead zone is anchored to the screen bottom in window coordinates (it tracks the BottomNavigationView's measured strip), not to a specific layout slot.
The same components render correctly when mounted at a root-level route outside the (tabs) group, in the same app build, on the same device. iOS and the Android emulator do not reproduce.
JS → native chain traced
This chain should make BottomNavigationView untouchable when tabBarHidden=true:
expo-router/unstable-native-tabs/NativeTabsView.android.js:25 forwards tabBarHidden={props.hidden} to Tabs.Host.
TabsHost.kt:50 proxies to container.tabBarHidden.
TabsContainer.kt:147-155 setter posts flushPendingUpdates().
performContainerUpdate → updateBottomNavigationViewAppearanceIfNeeded → appearanceCoordinator.updateTabAppearance.
TabsAppearanceApplicator.kt:38: bottomNavigationView.isVisible = !isTabBarHidden.
isVisible = false translates to visibility = View.GONE via the androidx KTX extension, which by Android semantics means no layout, no draw, no hit-test. Empirically the touch IS consumed inside the TabsContainer subtree, so one of:
- the visibility update never runs / isn't running in time
- a later layout pass restores
View.VISIBLE
- the eater is a different view inside the
TabsContainer subtree (TabsScreen ViewGroup, an inset listener, etc.)
A adb shell uiautomator dump on the foregrounded failing screen would confirm the actual native view state.
Steps to reproduce
- Build the minimal repro to a physical Android device. (See file mapping in
00-README.md.)
- From Home tab, tap Open /detail — Stack pushes a screen inside
(tabs) with tabBarHidden=true.
- Tap the static red BOTTOM button — does not fire.
- In the scrollable list, scroll any row INTO the bottom ~56dp strip and tap it — does not fire as long as the row sits visually in the strip. Scroll it up by a few pixels — tap fires normally.
- From Home tab, tap Open /control — Stack pushes the SAME screen content at root, outside
(tabs).
- Repeat the same taps on
/control — all fire, including the static BOTTOM button and any scrolled-in row.
Snack or a link to a repository
https://gist.github.com/antekordic/4a4b03883842d9e4a769d4f139ada8a1
Screens version
4.25.2
React Native version
0.85.3
Platforms
Android
JavaScript runtime
Hermes
Workflow
Expo managed workflow (expo SDK 56, expo-router 56.2.7, expo-router/unstable-native-tabs)
Architecture
Fabric (New Architecture)
Build type
Debug mode (also confirmed in release dev-client builds)
Device
Real device
Device model
Samsung Galaxy A17 (SM-A176B), Android 16, 3-button nav. Does NOT reproduce on Android emulator or iOS.
Acknowledgements
Yes — searched #2150, #2219, #1663, and expo/expo #41781; none describe this specific symptom (bottom-strip touch consumption on Stack-pushed screens under NativeTabs hidden=true, including scrolled content).
Description
When a Stack-pushed screen is a child of
<NativeTabs hidden={true}>(i.e.<Tabs.Host tabBarHidden={true}>on Android), anyPressable/TouchableOpacityrendered in the bottom ~56dp strip of the visible screen does not fireonPresson Android. The dead-zone width matches theBottomNavigationView's default height.This affects both:
Pressableanchored to the bottom of the screen never fires.Pressableinside aScrollView/FlatListfires when scrolled above the strip, but stops firing the moment it scrolls into the bottom ~56dp. Scroll the same row a few pixels up and it works again. This proves the dead zone is anchored to the screen bottom in window coordinates (it tracks the BottomNavigationView's measured strip), not to a specific layout slot.The same components render correctly when mounted at a root-level route outside the
(tabs)group, in the same app build, on the same device. iOS and the Android emulator do not reproduce.JS → native chain traced
This chain should make
BottomNavigationViewuntouchable whentabBarHidden=true:expo-router/unstable-native-tabs/NativeTabsView.android.js:25forwardstabBarHidden={props.hidden}toTabs.Host.TabsHost.kt:50proxies tocontainer.tabBarHidden.TabsContainer.kt:147-155setter postsflushPendingUpdates().performContainerUpdate→updateBottomNavigationViewAppearanceIfNeeded→appearanceCoordinator.updateTabAppearance.TabsAppearanceApplicator.kt:38:bottomNavigationView.isVisible = !isTabBarHidden.isVisible = falsetranslates tovisibility = View.GONEvia the androidx KTX extension, which by Android semantics means no layout, no draw, no hit-test. Empirically the touch IS consumed inside theTabsContainersubtree, so one of:View.VISIBLETabsContainersubtree (TabsScreen ViewGroup, an inset listener, etc.)A
adb shell uiautomator dumpon the foregrounded failing screen would confirm the actual native view state.Steps to reproduce
00-README.md.)(tabs)withtabBarHidden=true.(tabs)./control— all fire, including the static BOTTOM button and any scrolled-in row.Snack or a link to a repository
https://gist.github.com/antekordic/4a4b03883842d9e4a769d4f139ada8a1
Screens version
4.25.2
React Native version
0.85.3
Platforms
Android
JavaScript runtime
Hermes
Workflow
Expo managed workflow (expo SDK 56, expo-router 56.2.7,
expo-router/unstable-native-tabs)Architecture
Fabric (New Architecture)
Build type
Debug mode (also confirmed in release dev-client builds)
Device
Real device
Device model
Samsung Galaxy A17 (SM-A176B), Android 16, 3-button nav. Does NOT reproduce on Android emulator or iOS.
Acknowledgements
Yes — searched #2150, #2219, #1663, and expo/expo #41781; none describe this specific symptom (bottom-strip touch consumption on Stack-pushed screens under
NativeTabs hidden=true, including scrolled content).