Loading...
Loading...
.NET MAUI safe area and edge-to-edge layout guidance for .NET 10+. Covers the new SafeAreaEdges property, SafeAreaRegions enum, per-edge control, keyboard avoidance, Blazor Hybrid CSS safe areas, migration from legacy iOS-only APIs, and platform-specific behavior for Android, iOS, and Mac Catalyst. USE FOR: "safe area", "edge-to-edge", "SafeAreaEdges", "SafeAreaRegions", "keyboard avoidance", "notch insets", "status bar overlap", "iOS safe area", "Android edge-to-edge", "content behind status bar", "UseSafeArea migration", "soft input keyboard", "IgnoreSafeArea replacement". DO NOT USE FOR: general layout or grid design (use Grid and StackLayout), app lifecycle handling (use maui-app-lifecycle), theming or styling (use maui-theming), or Shell navigation structure.
npx skill4agent add dotnet/skills maui-safe-areaUseSafeAreaIgnoreSafeAreaSafeAreaEdgesSafeAreaRegionsThis is new API surface in .NET 10. If the project targets .NET 9 or earlier, these APIs do not exist. Guide the developer to the legacyandios:Page.UseSafeAreaproperties instead.Layout.IgnoreSafeArea
ios:Page.UseSafeAreaLayout.IgnoreSafeAreaWindowSoftInputModeAdjust.Resizeenv(safe-area-inset-*)net10.0-*[Flags]
public enum SafeAreaRegions
{
None = 0, // Edge-to-edge — no safe area padding
SoftInput = 1 << 0, // Pad to avoid the on-screen keyboard
Container = 1 << 1, // Stay inside status bar, notch, home indicator
Default = -1, // Use the platform default for the control type
All = 1 << 15 // Respect all safe area insets (most restrictive)
}SoftInputContainerSafeAreaRegions.Container | SafeAreaRegions.SoftInputpublic readonly struct SafeAreaEdges
{
public SafeAreaRegions Left { get; }
public SafeAreaRegions Top { get; }
public SafeAreaRegions Right { get; }
public SafeAreaRegions Bottom { get; }
// Uniform — same value for all four edges
public SafeAreaEdges(SafeAreaRegions uniformValue)
// Horizontal / Vertical
public SafeAreaEdges(SafeAreaRegions horizontal, SafeAreaRegions vertical)
// Per-edge
public SafeAreaEdges(SafeAreaRegions left, SafeAreaRegions top,
SafeAreaRegions right, SafeAreaRegions bottom)
}SafeAreaEdges.NoneSafeAreaEdges.AllSafeAreaEdges.Default<!-- Uniform -->
SafeAreaEdges="Container"
<!-- Horizontal, Vertical -->
SafeAreaEdges="Container, SoftInput"
<!-- Left, Top, Right, Bottom -->
SafeAreaEdges="Container, Container, Container, SoftInput"| Control | Default | Notes |
|---|---|---|
| | Edge-to-edge. Breaking change from .NET 9 on Android. |
| | Respects bars/notch, flows under keyboard |
| | iOS maps to automatic content insets. Only |
| | Inherits parent behavior |
| | Inherits parent behavior |
NoneContentPageContainerNone<!-- .NET 10 default — content extends under status bar -->
<ContentPage>
<!-- Restore .NET 9 Android behavior -->
<ContentPage SafeAreaEdges="Container">WindowSoftInputModeAdjust.ResizeSafeAreaEdges="All"NoneContainer<ContentPage SafeAreaEdges="None">
<Grid SafeAreaEdges="None">
<Image Source="background.jpg" Aspect="AspectFill" />
<VerticalStackLayout Padding="20" VerticalOptions="End">
<Label Text="Overlay text" TextColor="White" FontSize="24" />
</VerticalStackLayout>
</Grid>
</ContentPage><ContentPage SafeAreaEdges="All">
<VerticalStackLayout Padding="20">
<Label Text="Safe content" FontSize="18" />
<Entry Placeholder="Enter text" />
<Button Text="Submit" />
</VerticalStackLayout>
</ContentPage><ContentPage>
<Grid RowDefinitions="*,Auto"
SafeAreaEdges="Container, Container, Container, SoftInput">
<ScrollView Grid.Row="0">
<VerticalStackLayout Padding="20" Spacing="10">
<Label Text="Messages" FontSize="24" />
</VerticalStackLayout>
</ScrollView>
<Border Grid.Row="1" BackgroundColor="LightGray" Padding="20">
<Grid ColumnDefinitions="*,Auto" Spacing="10">
<Entry Placeholder="Type a message..." />
<Button Grid.Column="1" Text="Send" />
</Grid>
</Border>
</Grid>
</ContentPage><ContentPage SafeAreaEdges="None">
<Grid RowDefinitions="Auto,*,Auto">
<Grid BackgroundColor="{StaticResource Primary}">
<Label Text="App Header" TextColor="White" Margin="20,40,20,20" />
</Grid>
<ScrollView Grid.Row="1" SafeAreaEdges="Container">
<!-- Use Container, not All — ScrollView only honors Container and None -->
<VerticalStackLayout Padding="20">
<Label Text="Main content" />
</VerticalStackLayout>
</ScrollView>
<Grid Grid.Row="2" SafeAreaEdges="SoftInput"
BackgroundColor="LightGray" Padding="20">
<Entry Placeholder="Type a message..." />
</Grid>
</Grid>
</ContentPage>var page = new ContentPage
{
SafeAreaEdges = SafeAreaEdges.All
};
var grid = new Grid
{
SafeAreaEdges = new SafeAreaEdges(
left: SafeAreaRegions.Container,
top: SafeAreaRegions.Container,
right: SafeAreaRegions.Container,
bottom: SafeAreaRegions.SoftInput)
};| Scenario | SafeAreaEdges value |
|---|---|
| Forms, critical inputs | |
| Photo viewer, video player, game | |
| Scrollable content with fixed header/footer | |
| Chat/messaging with bottom input bar | Per-edge: |
| Blazor Hybrid app | |
<ContentPage SafeAreaEdges="None">
<BlazorWebView HostPage="wwwroot/index.html">
<BlazorWebView.RootComponents>
<RootComponent Selector="#app" ComponentType="{x:Type local:Routes}" />
</BlazorWebView.RootComponents>
</BlazorWebView>
</ContentPage>viewport-fit=coverindex.html<meta name="viewport" content="width=device-width, initial-scale=1.0,
maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />env()body {
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
padding-right: env(safe-area-inset-right);
}env(safe-area-inset-top)env(safe-area-inset-bottom)env(safe-area-inset-left)env(safe-area-inset-right)| Legacy (.NET 9 and earlier) | New (.NET 10+) |
|---|---|
| |
| |
| |
IgnoreSafeArea="True"SafeAreaRegions.None<!-- .NET 9 (legacy, iOS-only) -->
<ContentPage xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
ios:Page.UseSafeArea="True">
<!-- .NET 10+ (cross-platform) -->
<ContentPage SafeAreaEdges="Container">SoftInputScrollViewDefaultUIScrollViewContentInsetAdjustmentBehavior.Automatic<Shell Shell.BackgroundColor="#80000000" Shell.NavBarHasShadow="False" />SoftInputWindowInsetsCompatWindowInsetsAnimationCompatNoneContentPage SafeAreaEdges="None"ContainerNoneSoftInputSoftInputSoftInputDefaultNoneDefaultNoneSafeAreaEdges="Container"env(safe-area-inset-*)viewport-fit=coverenv(safe-area-inset-*)ContentPageNoneContainerSafeAreaEdges="Container"ios:Page.UseSafeAreaSafeAreaEdgesSafeAreaEdges="Container"NoneSafeAreaEdgesviewport-fit=coverindex.html<meta viewport>UseSafeAreaIgnoreSafeAreaSafeAreaEdges