Skip to content

[Android][NativeTabs] Pressables in bottom ~56dp of Stack-pushed screens don't fire when hidden=true (also affects scrolled rows) #4132

@antekordic

Description

@antekordic

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().
  • performContainerUpdateupdateBottomNavigationViewAppearanceIfNeededappearanceCoordinator.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

  1. Build the minimal repro to a physical Android device. (See file mapping in 00-README.md.)
  2. From Home tab, tap Open /detail — Stack pushes a screen inside (tabs) with tabBarHidden=true.
  3. Tap the static red BOTTOM button — does not fire.
  4. 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.
  5. From Home tab, tap Open /control — Stack pushes the SAME screen content at root, outside (tabs).
  6. 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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    platform:androidIssue related to Android part of the libraryrepro-providedA reproduction with a snack or repo is provided

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions