Technical
How to Prevent Keyboard Layout Shifts in Android TWAs
November 11, 2026 · 6 min read
Understanding Keyboard Layout Shifts in TWAs
When an Android user taps on an input field inside a Trusted Web Activity, the operating system launches the virtual keyboard. By default, this action alters the screen real estate available to your application. If not managed correctly, this causes elements to shift unpredictably, inputs to be hidden behind the keyboard, or the entire web viewport to squash.
Because a TWA runs inside a customised Chrome custom tab container, it relies on a combination of native Android window configuration rules and web-based rendering standards to handle keyboard events. If the native container and the CSS layout disagree on how to handle the sudden loss of height, the user experience suffers. Users may experience jumping headers, clipped forms, or input boxes that lose focus immediately after tapping.
How Android Manifest Settings Affect Viewport Resizing
The Android operating system offers different configurations for handling the soft keyboard through the windowSoftInputMode attribute within the AndroidManifest.xml file. In a TWA app, this native configuration determines whether the container resizes the web browser window or pans the screen to keep the active input in view.
There are three main configurations for this attribute, each altering how the native window boundaries behave when the input method editor opens:
| Configuration Mode | Native Android Behaviour | Effect on Web Layout inside TWA |
|---|---|---|
| adjustResize | Resizes the layout container to fit the remaining screen space. | Triggers a resize event in JavaScript. Shrinks the viewport height. Pushes up absolute-positioned elements. |
| adjustPan | Shifts the entire layout window upward without changing its size. | The viewport height remains unchanged, but parts of the top header or layout may slide off the screen. |
| adjustNothing | Does not resize or pan the native window. | The keyboard overlays the web content completely. The web app must handle scroll positioning manually. |
For most Progressive Web Apps converted to TWAs, the default behaviour is adjustResize. While adjustResize ensures that the active input remains visible, it often breaks layouts that rely on absolute positioning, such as floating navigation bars or sticky action buttons at the bottom of the screen. When the viewport height drops drastically, these elements are pushed directly above the keyboard, covering the form fields.
Using CSS Interactive Widget to Control Keyboard Behaviour
Modern browser engines provide web developers with direct control over how the web viewport responds to virtual keyboards without modifying native Android code. This is achieved using the interactive-widget value in the viewport meta tag.
By default, when the virtual keyboard is triggered, browsers choose how to adjust the layout viewport. You can explicitly override this behaviour by setting the viewport meta tag to one of three values:
- resizes-visual: The virtual keyboard resizes only the visual viewport, leaving the layout viewport untouched. This prevents sticky footers and absolute positioned elements from leaping up the screen, as they remain anchored to the bottom of the larger layout viewport.
- resizes-content: The virtual keyboard resizes both the visual and layout viewports. This matches the classic adjustResize native behaviour, shrinking your page layout and forcing footer navigation upward.
- overlays-content: The virtual keyboard does not resize any viewport. It simply draws over the top of the content. This is useful when you want to handle scrolling and positioning entirely through custom script logic.
To implement this control, update the meta tag in the head element of your web application:
<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-visual">
Using resizes-visual is generally the preferred configuration for modern single-page applications. It keeps your primary layout steady while allowing the visual viewport to shift dynamically, preventing the layout shifts that disrupt the visual hierarchy of your application.
Implementing the JavaScript VirtualKeyboard API
For highly dynamic applications, relying purely on CSS meta tags might not be sufficient. The VirtualKeyboard API allows developers to programmatically control the keyboard and adapt the interface using CSS environment variables and JavaScript listeners.
First, you must instruct the browser not to resize the viewport automatically when the keyboard opens. This is done by setting the overlaysContent property to true on the virtualKeyboard interface:
if ("virtualKeyboard" in navigator) { navigator.virtualKeyboard.overlaysContent = true; }
Once overlaysContent is enabled, the virtual keyboard will overlap your application content without altering layout boundaries. To ensure that input fields are not hidden beneath the keyboard, you can use the standardised CSS environment variables to add dynamic padding to your page layouts:
- keyboard-inset-top: Represents the distance from the top of the viewport to the top edge of the keyboard.
- keyboard-inset-height: Represents the physical height of the virtual keyboard.
- keyboard-inset-bottom: Represents the distance from the bottom of the viewport to the bottom edge of the keyboard.
These values can be integrated into your stylesheets to dynamically shift elements when the keyboard is active. For example, if you have a form container that requires padding at the bottom when the keyboard is open, you can apply the environment variable directly:
.form-container { padding-bottom: env(keyboard-inset-height, 0px); }
This method ensures that only the container containing your active form inputs receives additional padding, while your overall page layout, headers, and backgrounds remain completely stable and unaffected by layout shifts.
A Checklist for Visual Testing
To verify that your keyboard-handling implementation works correctly inside your compiled APK or AAB, follow this testing methodology on a physical Android device or emulator:
- Test in both light and dark themes: Confirm that the background colour of the virtual keyboard container does not cause flickering or visual contrast issues with your app content.
- Check scrollable containers: Verify that form fields located near the bottom of long scrollable screens can still be scrolled fully into view when the keyboard is active.
- Monitor focus loss: Ensure that tapping outside an input field successfully hides the virtual keyboard and restores the viewport boundaries cleanly.
- Verify floating action buttons: Confirm that floating action buttons, sticky footers, or bottom navigation menus are either hidden programmatically or remain stationary under the visual viewport bounds, rather than hovering mid-screen over input boxes.
Ready to build for Android and iOS?
€49.99 once includes unlimited Android APK and AAB plus iOS IPA builds, all from one dashboard.
Build my app