Posted in

Capacitor.js: disable edge-to-edge on Android 15

If you’re building a web app with Capacitor.js and targeting Android 15 (API 35), you’ll likely run into the edge-to-edge issue: your app content renders behind the status bar and navigation buttons. This post explains what’s happening and how to fix it.

The problem

Android 15 enforces edge-to-edge display by default. This means your WebView extends behind the system bars (status bar at the top, navigation bar at the bottom), and your app header and footer end up partially hidden.

In our case, the header buttons were half-covered by the status bar, and the paging buttons at the bottom were behind the Android navigation buttons.

What didn’t work

We tried several approaches before finding one that works reliably across Android 14 and 15:

fitsSystemWindows=true in styles.xml — This XML attribute on the theme didn’t propagate to the Capacitor WebView.

WindowCompat.setDecorFitsSystemWindows(window, true) — This used to work, but Android 15 ignores it. Edge-to-edge is mandatory.

setStatusBarColor / setNavigationBarColor — These are deprecated in API 35. Android 15 overrides them and makes the system bars transparent regardless.

What worked

Two things working together in MainActivity.java:

1. Window background color

Since Android 15 forces transparent system bars, you need to control what’s visible behind them. Setting the window’s background drawable to match your app’s header/chrome color ensures the areas behind the system bars aren’t white or black.

2. WindowInsets padding listener

An insets listener on the content view applies the system bar dimensions as padding, pushing the WebView content inward so nothing renders behind the bars.

The code

package net.dynart.bible;

import android.os.Bundle;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.view.View;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.graphics.Insets;
import com.getcapacitor.BridgeActivity;

public class MainActivity extends BridgeActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Set the window background so the area behind transparent system bars
        // matches the app header color instead of showing white/black
        getWindow().setBackgroundDrawable(
            new ColorDrawable(Color.parseColor("#3b3f4a"))
        );

        // Apply padding for system bar insets so content is not behind system bars
        View content = findViewById(android.R.id.content);
        ViewCompat.setOnApplyWindowInsetsListener(content, (view, windowInsets) -> {
            Insets insets = windowInsets.getInsets(
                WindowInsetsCompat.Type.systemBars()
            );
            view.setPadding(insets.left, insets.top, insets.right, insets.bottom);
            return WindowInsetsCompat.CONSUMED;
        });
    }
}

Replace #3b3f4a with whatever color matches your app’s chrome/header.

Optional: CSS safe area insets

As a belt-and-suspenders approach (and for future iOS support), you can also add CSS safe area padding. First, update your viewport meta tag:

<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">

Then add safe area insets to your header and footer:

.app-header {
  padding: calc(12px + env(safe-area-inset-top, 0px)) 20px 12px;
}

.paging-bar {
  padding: 10px 20px calc(10px + env(safe-area-inset-bottom, 0px));
}

On Android, the Java-side insets listener is what actually solves the problem. The CSS insets are a no-op there since the WebView is already padded correctly, but they’ll help on iOS where you don’t have the native insets listener.

Summary

Android 15 forces edge-to-edge and deprecates the old APIs for controlling system bar colors. For Capacitor.js apps, the fix is:

  1. getWindow().setBackgroundDrawable(...) — controls the color behind transparent system bars
  2. ViewCompat.setOnApplyWindowInsetsListener(...) — pads the content view away from system bars

No deprecated APIs, works on Android 14 and 15, and takes about 10 lines of Java.