Skip to content

Blend the system bars into the theme with native safe areas#107

Closed
danielchalmers wants to merge 3 commits into
mainfrom
claude/edge-to-edge
Closed

Blend the system bars into the theme with native safe areas#107
danielchalmers wants to merge 3 commits into
mainfrom
claude/edge-to-edge

Conversation

@danielchalmers

@danielchalmers danielchalmers commented Jul 17, 2026

Copy link
Copy Markdown
Owner

What

Makes the system bars feel like part of the app on Android without any custom inset plumbing. The app targets SDK 36 where bars are transparent overlays, and previously the safe area padding around the web view showed as a plain white strip.

  • MainPage uses SafeAreaEdges="All", the supported MAUI mechanism: the page letterboxes the BlazorWebView inside the safe area and handles the keyboard natively.
  • The page background follows the Material 3 surface tone (and updates with theme and dark mode changes), so the safe area padding blends seamlessly with the app instead of showing white. On Android 15+ the transparent bars sit on that background; on Android 14 and below the bars stay opaque and are tinted to the same tone, including the navigation bar which was never themed before.
  • UpdateStatusBar becomes UpdateSystemBars: bar icon contrast now follows dark mode on both bars through WindowInsetsControllerCompat.
  • Removes the dead safe-area CSS that was gated behind an iOS-only @supports query along with its hardcoded colors and spacer div. In its place the stylesheet consumes env(safe-area-inset-*) variables that resolve to zero while letterboxed, so if edge-to-edge is enabled later (once MAUI's SoftInput safe area mode works correctly and WebView 140+ is widespread) the web UI pads itself with no further changes.

Why not true edge-to-edge

An earlier revision of this PR drew under the bars with a custom service that bridged window insets into CSS variables plus a keyboard resize workaround. That was rolled back in favor of the native mechanism: for this app's design (opaque sticky header in the surface color) letterboxing on a themed background is visually near-identical, and it keeps zero custom platform code. The env() variables above leave the door open.

Verification

On the API 35 emulator: bars blend with the theme in light and dark with correct icon contrast, and dialogs with focused inputs sit fully above the keyboard (native resize confirmed via WebView bounds). 236/236 tests pass; Android and Windows targets build clean.

The web UI now extends under the transparent status and navigation bars.
An insets listener on the BlazorWebView injects safe area values as CSS
custom properties, with env() as a fallback for newer WebViews, since
env(safe-area-inset-*) is unreliable below Chromium 140. The sticky page
header absorbs the top inset so the status bar always sits on the app
bar surface, and the page body pads by the bottom inset so content
scrolls under the gesture bar.

Bar icon contrast now follows dark mode through the insets controller.
Android 14 and below keep opaque bars tinted to the M3 surface, and the
navigation bar is now themed there too.

Verified on the API 35 emulator in light and dark, with the bridge
proven by disabling the env() fallback, and keyboard resize intact.
The insets listener now tracks the IME inset and pads the activity
content frame by the keyboard height, shrinking the web viewport so
dialogs re-center above the keyboard and focused inputs scroll into
view, matching the old adjustResize behavior. While the keyboard is
open the CSS bottom inset drops to zero because the viewport already
ends at the keyboard.

Verified on the API 35 emulator: the note dialog and its actions stay
above the keyboard (WebView 1080x1517 while open) and the viewport
restores to full height on dismiss.
Letterboxing through SafeAreaEdges is the supported MAUI mechanism, so
the custom SafeAreaService and its keyboard workaround are gone. The
page background now follows the M3 surface tone, which makes the safe
area padding around the web view blend into the app, and MAUI handles
the keyboard natively again.

The web UI keeps env(safe-area-inset-*) variables that are inert while
letterboxed but light up if edge-to-edge is enabled once MAUI's
SoftInput mode is fixed and WebView 140+ is widespread.

Verified on the API 35 emulator: seamless bars in light and dark, and
dialogs with focused inputs sit above the keyboard.
@danielchalmers danielchalmers changed the title Go edge-to-edge on Android Blend the system bars into the theme with native safe areas Jul 17, 2026
@danielchalmers

Copy link
Copy Markdown
Owner Author

Closing this. The supported non-custom approach cannot theme the transparent system navigation bar on API 35+: with SafeAreaEdges="All" the page is letterboxed inside the bars, so the transparent nav bar reveals the uncolored window background and renders black (most visible with 3-button navigation). Doing it properly needs true edge-to-edge, which is blocked upstream for Blazor Hybrid by dotnet/maui#34462 (milestone .NET 10 SR9), and we chose not to maintain a hand-rolled insets bridge for it.

Shelving until we take an SR9 servicing bump. Tracked in #110, which lists the MAUI issues to subscribe to. The reference implementation stays on the claude/edge-to-edge branch.

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.

1 participant