Skip to content

[Bug]: Incorrect visualViewport/innerHeight values on Android < 15: UI partially overlapped by keyboard #8181

@Ashe3

Description

@Ashe3

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

@capacitor/cli: 7.4.3
@capacitor/core: 7.4.3
@capacitor/android: 7.4.3
@capacitor/ios: 7.4.3

Installed Dependencies:

@capacitor/cli: 7.4.3
@capacitor/android: 7.4.3
@capacitor/core: 7.4.3
@capacitor/ios: 7.4.3

[success] iOS looking great! 👌
[success] Android looking great! 👌

Other API Details

npm --version output: 10.9.2
node --version output: v22.17.0
pod --version output: 1.15.2

Platforms Affected

  • iOS
  • Android
  • Web

Current Behavior

Summary

After introducing new WebView resize settings (adjustMarginsForEdgeToEdge: 'force', Keyboard.resizeOnFullScreen: true) to support edge-to-edge and better keyboard handling on Android, an issue has been identified on Android < 15.

Problem Details

  • On devices running Android < 15, when the keyboard is open and navigation buttons or gesture navigation are enabled, the values of window.visualViewport.height and window.innerHeight do not account for the bottom navigation bar.
  • As a result, modals sized using these values are partially overlapped by the keyboard (specifically, the bottom area). The "Save" button and other lower UI elements become inaccessible.
  • CSS variables like safe-area-inset-bottom are always zero, so padding-bottom is not automatically added. As far as I understand, this is expected when these settings are used.

How the Issue Manifests

  • On Android < 15 (e.g., OnePlus 12r, Android 14, Samsung S23 Android 13, Pixel 8 Android 14), when opening a modal and the keyboard appears:
    • The calculated modal height (visualViewport.height or window.innerHeight) does not account for the bottom bar.
    • If the modal is anchored to the bottom or uses full available height up to the keyboard, its bottom part is covered by the keyboard.
    • safe-area-inset-bottom is not available, padding-bottom == 0.
  • On Android 15+ (adjustMarginsForEdgeToEdge: 'force'), this issue does not occur because the system correctly subtracts the height of navigation elements from the available viewport.

Logs Demonstrating the Issue

  • Android 14 OnePlus 12R (problem):
    • screen.height = 795
    • window.innerHeight (without keyboard) = 710 → difference 85px (navigation bar)
    • With keyboard open: window.innerHeight = 499
    • The navigation bar still takes up 44px at the bottom—UI is overlapped.
    • safe-area-inset-bottom = 0px
    • Keyboard heigh: 299 pixels
  • Android 15 OnePlus 13R (ok):
    • screen.height = 795
    • window.innerHeight (without keyboard) = 710 → same difference
    • With keyboard open: window.innerHeight = 455
    • The system correctly shrinks the viewport, UI is not overlapped.
    • safe-area-inset-bottom = 0px (but still compensated at the viewport level)
    • Keyboard height: 299 pixels

Visual Examples

Android 13 Android 15

Why This Matters

  • On older Android devices, the UI breaks when entering text in modals: part of the buttons and lower content are hidden by the keyboard.
  • The issue reliably reproduces on all Android < 15 devices with navigation buttons or gesture navigation enabled.
  • Without a way to correctly obtain the bottom safe-area-inset height, we have to use workarounds or hacks, making code maintenance harder and degrading UX on legacy devices.

Expected Behavior

What Is Needed

  • Viewport height should be calculated correctly on all Android versions supported by WebView/Capacitor, so that modal and fixed UI elements are never overlapped by the keyboard or navigation bar. This is expected behavior for modern mobile web libraries.
  • Alternatively, an official API or method should exist to reliably obtain the bottom navigation bar/system panel height for use in layout calculations—making it possible to programmatically avoid UI overlap.

Currently, AFAIK there are no tools or APIs to obtain this data directly , so we are forced to manually estimate the panel height, which is not reliable and leads to inconsistent user experience across devices.

Project Reproduction

None

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions