Skip to content

fix(android): keep BottomNavigationView pinned under the keyboard in edge-to-edge#549

Open
rayabelcode wants to merge 1 commit into
callstack:mainfrom
rayabelcode:fix/android-bottom-nav-keyboard-inset
Open

fix(android): keep BottomNavigationView pinned under the keyboard in edge-to-edge#549
rayabelcode wants to merge 1 commit into
callstack:mainfrom
rayabelcode:fix/android-bottom-nav-keyboard-inset

Conversation

@rayabelcode

Copy link
Copy Markdown
Contributor

What

Under edge-to-edge on Android, focusing a text input pushes the native tab bar up on top of the keyboard instead of letting the keyboard overlay it (iOS behavior). Fixes #357.

Why

The library delegates inset handling to Material. BottomNavigationView installs a default inset listener in its constructor that adds getSystemWindowInsetBottom() to its bottom padding, and that value includes the IME inset. With decorFitsSystemWindows=false the window is not resized, so the IME inset propagates down to the bar and Material pads it by the keyboard height every frame (material-components/material-components-android#493). windowSoftInputMode="adjustPan" does not help when react-native-keyboard-controller is present, since it forces adjustResize at runtime.

How

Give ExtendedBottomNavigationView its own OnApplyWindowInsetsListener that applies system bars + display cutout insets only, excluding Type.ime(), and returns the insets unconsumed so sibling views (the tab-screen content that hosts inputs) still receive the IME inset. Gesture-nav clearance is preserved because system-bar and cutout insets are still applied as padding.

This is a no-op outside edge-to-edge: with decorFitsSystemWindows=true the decor consumes the system insets before they reach the bar, so the computed insets are zero and padding stays at its base, and the keyboard resizes the window rather than dispatching an IME inset. Behavior only changes for the edge-to-edge case that is currently broken.

Test plan

  • Edge-to-edge app, tab-root screen with a top input: focus the input, confirm the tab bar stays pinned and the keyboard overlays it.
  • Form screen with a bottom input inside a tab: confirm keyboard avoidance still works.
  • Non-edge-to-edge build: confirm no change (bar still clears the nav bar, keyboard resizes as before).
  • Landscape / gesture-nav and 3-button nav: confirm the bar still clears the system nav bar.

…edge-to-edge

Material's BottomNavigationView adds the bottom system-window inset, which
includes the IME inset under edge-to-edge, to its own padding, so the native
tab bar rises above the keyboard. Give ExtendedBottomNavigationView its own
inset listener applying system bars and display cutout insets only, excluding
the IME type, and return the insets unconsumed so tab-screen inputs still
receive keyboard avoidance. This is a no-op outside edge-to-edge.

Fixes callstack#357
@HaraldHenriksson

Copy link
Copy Markdown

We independently root-caused this exact bug in a production React Native app and arrived at the same fix as this PR before finding it — confirming the approach from a second angle.

New data worth having for the merge decision: this now reproduces even in apps that were previously shielded. Our app wraps everything in react-native-keyboard-controller's KeyboardProvider, whose root-level IME-inset consumption used to prevent the insets from ever reaching BottomNavigationView. On the newest OS builds, consumed insets are dispatched to descendants anyway, so the Material bar keyboard-avoids regardless:

Device OS Tab bar above keyboard?
Pixel 10 Pro Android 17 🔴 yes
Stock emulator API 37.1 (Android 17) 🔴 yes
Galaxy S26 Ultra Android 16, newest One UI 8.x 🔴 yes
Galaxy S22 Ultra Android 16, One UI 8.0 🟢 no
Emulator API 35 🟢 no

Same APK everywhere — the trigger is purely the OS build, so this is switching on device-by-device as Android 17 / One UI updates roll out. All input fields, every screen with the native bar.

Verification of this PR's fix: we shipped the identical change via patch-package and confirmed on-device — Android 17 emulator, S26 Ultra and Pixel 10 Pro fixed (keyboard overlays the bar again), and no visual change at rest on the previously-working devices (system-bar/cutout padding preserved). Would love to see this merged + released so we can drop the patch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Android] Tab bar sticks to keyboard instead of being hidden behind it

2 participants