Safe areas, visualized

How the shell avoids notches and home indicators

Toggle the overlays below to highlight the top and bottom insets — then notice the header and tab bar already keep clear of them.

Show insets

Paint the safe areas orange so you can see exactly what the shell is padding.

AppShell pads the whole shell

One prop, and every fixed element respects the device. The header grows by the top inset so the status bar never sits on your logo; the tab bar grows by the bottom inset so the home indicator never covers a button.

This demo runs with safeArea on — that’s the extra breathing room you can see above the logo right now.

<AppShell safeArea>

Keep the top inset on a static header

A static header scrolls away with the page, so it normally gives its safe-area padding back too. Set forceSafeAreaTop to keep the top inset applied while the header is at rest — no content jump when the page settles at the top.

<Header behavior="static" forceSafeAreaTop />

SafeArea pads any region

For full-bleed regions — maps, carousels, video — wrap just that region and pick the edges it should respect. The live box below is wrapped in a SafeArea with left and right edges:

This box is padded by env(safe-area-inset-left) and env(safe-area-inset-right)

In portrait this phone reports 0px on the sides, so the dashed frame hugs the box. Rotate a real device to landscape and the box pulls in from the notch.

<SafeArea edges={["left", "right"]}>

Where the numbers come from

The platform standard, on iOS and Android alike: the browser exposes the notch and home-indicator geometry through env(safe-area-inset-*) once the page opts in with viewport-fit=cover. The shell reads those values directly — this docs mockup merely simulates an iPhone’s numbers inside the frame, since a desktop browser reports 0.

env(safe-area-inset-top)0px
env(safe-area-inset-bottom)0px
env(safe-area-inset-top) /* viewport-fit=cover */

The static tab bar below sits on the bottom inset — toggle the overlay to see the 34px it reserves.