Effortlessly enable edge-to-edge display in React Native, allowing your Android (v6 and above) app content to flow seamlessly beneath the system bars.
Tip
If you're running React Native 0.81 or later, consider using the built-in edgeToEdgeEnabled=true Gradle property along with @zoontek/react-native-navigation-bar instead.
This project has been built and is maintained thanks to the support from Expo.
This library follows the React Native releases support policy.
It is supporting the latest version, and the two previous minor series.
Recently, Google introduced a significant change: apps targeting SDK 35 will have edge-to-edge display enforced by default on Android 15+. Google is likely to mandate that app updates on the Play Store target SDK 35 starting on August 31, 2025. This assumption is based on the previous years' requirements following a similar timeline.
iOS has long used edge-to-edge displays, so adopting this design across all platforms ensures a consistent user experience. It also simplifies managing safe areas, eliminating the need for special cases specific to Android.
Immersive mode allows you to hide the status and navigation bars, making it ideal for full-screen experiences. Currently, the built-in StatusBar component uses FLAG_FULLSCREEN, a flag that has been deprecated since Android 11.
$ npm i -S react-native-edge-to-edge
# --- or ---
$ yarn add react-native-edge-to-edgeThis library requires you to update the parent of your Android AppTheme to an edge-to-edge version. Don't worry, it's very easy to understand! You just need to choose a theme based on the current value:
| If you currently have… | …you should use |
|---|---|
Theme.AppCompat.DayNight.NoActionBar |
Theme.EdgeToEdge |
Theme.MaterialComponents.DayNight.NoActionBar |
Theme.EdgeToEdge.Material2 |
Theme.Material3.DayNight.NoActionBar |
Theme.EdgeToEdge.Material3 |
Theme.Material3.DynamicColors.DayNight.NoActionBar |
Theme.EdgeToEdge.Material3.Dynamic |
Theme.Material3Expressive.DayNight.NoActionBar |
Theme.EdgeToEdge.Material3Expressive |
Theme.Material3Expressive.DynamicColors.DayNight.NoActionBar |
Theme.EdgeToEdge.Material3Expressive.Dynamic |
Theme.AppCompat.Light.NoActionBar |
Theme.EdgeToEdge.Light |
Theme.MaterialComponents.Light.NoActionBar |
Theme.EdgeToEdge.Material2.Light |
Theme.Material3.Light.NoActionBar |
Theme.EdgeToEdge.Material3.Light |
Theme.Material3.DynamicColors.Light.NoActionBar |
Theme.EdgeToEdge.Material3.Dynamic.Light |
Theme.Material3Expressive.Light.NoActionBar |
Theme.EdgeToEdge.Material3Expressive.Light |
Theme.Material3Expressive.DynamicColors.Light.NoActionBar |
Theme.EdgeToEdge.Material3Expressive.Dynamic.Light |
Add the library plugin in your app.json config file and create a new build 👷:
{
"expo": {
"plugins": [
[
"react-native-edge-to-edge",
{
"android": {
"parentTheme": "Default",
"enforceNavigationBarContrast": false
}
}
]
]
}
}📌 The available plugins options are:
type ParentTheme =
| "Default" // uses `Theme.EdgeToEdge`
| "Material2" // uses `Theme.EdgeToEdge.Material2`
| "Material3" // uses `Theme.EdgeToEdge.Material3`
| "Material3.Dynamic" // uses `Theme.EdgeToEdge.Material3.Dynamic`
| "Material3Expressive" // uses `Theme.EdgeToEdge.Material3Expressive`
| "Material3Expressive.Dynamic" // uses `Theme.EdgeToEdge.Material3Expressive.Dynamic`
| "Light" // uses `Theme.EdgeToEdge.Light`
| "Material2.Light" // uses `Theme.EdgeToEdge.Material2.Light`
| "Material3.Light" // uses `Theme.EdgeToEdge.Material3.Light`
| "Material3.Dynamic.Light" // uses `Theme.EdgeToEdge.Material3.Dynamic.Light`
| "Material3Expressive.Light" // uses `Theme.EdgeToEdge.Material3Expressive.Light`
| "Material3Expressive.Dynamic.Light"; // uses `Theme.EdgeToEdge.Material3Expressive.Dynamic.Light`
type Options = {
android?: {
// see the "Pick a parent theme" section
parentTheme?: ParentTheme; // optional (default: `Default`)
// see the "Transparent navigation bar" section
enforceNavigationBarContrast?: boolean; // optional (default: `true`)
};
};Note
These configuration properties are not supported in the Expo Go sandbox app, use a development build.
Edit your android/app/src/main/res/values/styles.xml file to inherit from one of the provided themes:
<resources>
<!-- update your AppTheme parent (see the "Pick a parent theme" section) -->
<style name="AppTheme" parent="Theme.EdgeToEdge">
<!-- … -->
<!-- disable the contrasting background of the navigation bar (optional) -->
<item name="enforceNavigationBarContrast">false</item>
</style>
</resources>By default, this library adopts Android 15 defaults: a fully transparent status bar, a fully transparent gesture navigation bar, and a semi-opaque button navigation bar. To enforce full transparency in all cases, set the enforceNavigationBarContrast option to false.
Note that by doing so, you will need to manage the navigation bar style (using SystemBars) in the same way you handle the status bar.
Enabling edge-to-edge display disrupts Android keyboard management (android:windowSoftInputMode="adjustResize"), requiring an alternative solution. While KeyboardAvoidingView is a viable option, we recommend using react-native-keyboard-controller for its enhanced capabilities.
Effective safe area management is essential to prevent content from being displayed behind transparent system bars. To achieve this, we highly recommend using react-native-safe-area-context, a well-known and trusted library.
React native built-in Modal component runs in its own native context, so be sure to set both the statusBarTranslucent and navigationBarTranslucent props to true. However, we recommend using the react-navigation modals or the expo-router modal screens instead.
Using StatusBar, expo-status-bar, or expo-navigation-bar in apps with edge-to-edge layout enabled may cause unexpected behavior, as they currently use deprecated APIs.
To address this, we provide a component to replace them and manage your app's system bars: <SystemBars />.
import { SystemBars } from "react-native-edge-to-edge";
// "auto" is based on current color scheme (light -> dark content, dark -> light content)
type Style = "auto" | "inverted" | "light" | "dark";
type SystemBarsProps = {
// set the color of the system bar content (as no effect on semi-opaque navigation bar)
style?: Style | { statusBar?: Style; navigationBar?: Style };
// hide system bars (the navigation bar cannot be hidden on iOS)
hidden?: boolean | { statusBar?: boolean; navigationBar?: boolean };
};
const App = () => (
<>
<SystemBars style="light" />
{/* … */}
</>
);Push a SystemBars entry onto the stack. The return value should be passed to popStackEntry when complete.
const entry: SystemBarsEntry = SystemBars.pushStackEntry(
props /*: SystemBarsProps */,
);Remove an existing SystemBars stack entry from the stack.
SystemBars.popStackEntry(entry /*: SystemBarsEntry */);Replace an existing SystemBars stack entry with new props.
const entry: SystemBarsEntry = SystemBars.replaceStackEntry(
entry /*: SystemBarsEntry */,
props /*: SystemBarsProps */,
);Set the system bars style.
SystemBars.setStyle(style /*: SystemBarsProps["style"] */);SystemBars.setHidden
Show or hide the system bars.
SystemBars.setHidden(style /*: SystemBarsProps["hidden"] */);If you're an author and your package interferes with edge-to-edge, refer to the react-native-is-edge-to-edge README.md for compatibility instructions.
There's currently an open issue with the Android 15 emulator image regarding the navigation bar style when it is is fully transparent. This issue does not occur on physical devices.
In recent months, support has been added across the React Native ecosystem. If you use any of the following libraries, make sure you're on the latest version:
expo-routergaleriareact-native-avoid-softinputreact-native-bootsplashreact-native-bottom-tabsreact-native-keyboard-controllerreact-native-reanimatedreact-native-screensreact-native-true-sheetreact-native-unistyles (v3)
Make also sure to replace all occurrences of the built-in StatusBar, expo-status-bar and expo-navigation-bar with SystemBars.