Fixing Content Hidden Behind the iOS Notch and Dynamic Island in React Native
A header title or button renders perfectly on an older iPhone and gets clipped by the notch or Dynamic Island on a newer one — sometimes on one screen but not another in the same app. The layout code isn't wrong for the device it was tested on; it's just not asking the OS how much space that specific device actually reserves.
The Problem
A screen's top content — a header title, a back button, a custom navigation bar — renders correctly on some iPhones and gets partially or fully hidden behind the notch or Dynamic Island on others. The same app can behave inconsistently even across its own screens: a stock navigator header handles it correctly, while a custom-built header a few screens later doesn't, or a modal presented over the main navigation stack ignores the safe area entirely even though the screen underneath it doesn't.
Why It Happens
A hardcoded pixel offset can't account for a value that differs by device generation
The vertical space actually reserved by a notch, a Dynamic Island, or no cutout at all (older devices, Android) is not a fixed number — it varies by device model and changes again whenever Apple introduces a new form factor. Code that hardcodes something like paddingTop: 44 to "clear the notch" is really just matching one specific device it happened to be tested on, and will be wrong — either insufficient or excessive — on every device with a different actual inset.
A custom header or overlay bypasses whatever safe-area handling the built-in navigator provides
A stock React Navigation header automatically accounts for the device's safe area insets as part of its own layout. The moment a screen replaces that with a custom header component, or renders content in an absolutely-positioned overlay outside the navigator's own layout system, that automatic handling goes with it — the custom component is now responsible for reading and applying the correct inset itself, and forgetting to do so is what produces the "some screens work, others don't" pattern.
Modals and portal-rendered content can render outside the safe-area provider's boundary
Content presented through a portal, a separate root view, or certain full-screen modal presentation styles doesn't automatically inherit the same safe-area context as the screen underneath it. If that separate render tree isn't itself wrapped by a safe-area provider, useSafeAreaInsets() called inside it can return zero or stale values, even though the same hook works correctly on the main screen.
Measuring available space with raw window dimensions ignores the reserved area entirely
Code that computes layout using Dimensions.get("window") gets the full screen dimensions with no awareness of how much of that space is actually usable — the notch, Dynamic Island, and home indicator all reduce the effectively safe content area without changing what Dimensions reports, so a layout calculated purely from window size will systematically overestimate available space at the top and bottom of the screen.
The Fix
1. Wrap the app root in SafeAreaProvider and use useSafeAreaInsets instead of a constant
import { SafeAreaProvider, useSafeAreaInsets } from "react-native-safe-area-context";
function App() {
return (
);
}
function CustomHeader() {
const insets = useSafeAreaInsets();
return {/* header content */} ;
}
useSafeAreaInsets() returns the device's actual current inset values at runtime, so the same code correctly adapts across a notch phone, a Dynamic Island phone, and a device with no cutout at all — replacing any hardcoded constant with this call is usually the single fix that resolves the majority of these cases.
2. Apply the top inset explicitly on every custom header or overlay, since it isn't automatic
Any component that replaces or renders outside the stock navigator header — a custom tab bar, a floating action button positioned near the top, a full-bleed hero image with overlaid text — needs to explicitly read and apply insets.top (or the relevant edge) itself, since that responsibility doesn't transfer automatically just because the rest of the screen is inset-aware.
3. Confirm modals and portal content are still inside the SafeAreaProvider tree
function AppRoot() {
return (
{/* must be inside the same provider */}
);
}
If a modal or full-screen overlay renders through a separate root view or portal, make sure that render tree is inside the same SafeAreaProvider as the rest of the app — a portal rendered as a sibling of the provider rather than a descendant of it will get incorrect inset values regardless of how the modal's own layout code is written.
4. Test on both a notch device and a Dynamic Island device, not just one
Since the actual inset values genuinely differ between device generations, a layout that looks correct on a single test device (simulator or physical) isn't sufficient confirmation — verify on at least one notch-style device and one Dynamic Island device, since a bug that only shows up on one of the two is exactly the kind of thing a hardcoded-constant fix tends to produce.
Why This Works
Every fix here replaces an assumption about a fixed offset with a runtime query for the device's actual current value. useSafeAreaInsets() is the single source of truth Apple's own APIs expose for this, and code that defers to it instead of a hardcoded number stays correct automatically as new device form factors ship. Explicitly applying insets on custom components closes the gap left by opting out of the stock navigator's automatic handling, and confirming the safe-area provider actually wraps modals and portals closes the gap where a separate render tree silently loses access to the correct context.
Conclusion
Content hidden behind the iOS notch or Dynamic Island in React Native is almost always a hardcoded offset or a missing safe-area context, not a rendering bug — the actual reserved space genuinely differs by device and can't be captured by a single constant. Use SafeAreaProvider and useSafeAreaInsets() instead of a fixed padding value, apply insets explicitly on any custom header or overlay, confirm modals and portals are inside the provider tree, and test on both a notch device and a Dynamic Island device before considering the fix verified.
