react-native-bounds
v0.4.2
Published
React Native helpers for screen bounds, safe area, notch, gesture navigation, status bar, and Android system bar insets.
Downloads
260
Maintainers
Readme
react-native-bounds
Reliable screen bounds, safe-area helpers, Android navigation-bar detection, status-bar height, and notch/cutout handling for React Native.
react-native-bounds gives you a small API for layouts that need to avoid the real edges of the device: status bars, waterdrop cameras, notches, home indicators, Android three-button navigation, and Android gesture areas.
Highlights
- Detects Android status bar height.
- Handles Android waterdrop camera and display cutout top insets.
- Detects Android three-button navigation bar space.
- Detects Android gesture navigation space when visible.
- Reads native Android
WindowInsetsfor production accuracy. - Falls back to JavaScript estimates if the native module is unavailable.
- Estimates iOS notch, Dynamic Island, and home indicator safe areas.
- Returns usable layout frame after insets.
- Recomputes on rotation and window-size changes.
- No extra runtime dependency.
Installation
npm install react-native-boundsor:
yarn add react-native-boundsExpo
This package includes Android native code. It works in Expo dev builds and prebuild/native projects.
It will not load the Android native module inside Expo Go.
npx expo run:androidQuick Start
import React from "react";
import { Text, View } from "react-native";
import { useScreenSafeArea } from "react-native-bounds";
export default function App() {
const bounds = useScreenSafeArea();
return (
<View
style={{
flex: 1,
paddingTop: bounds.insets.top,
paddingBottom: bounds.insets.bottom,
paddingLeft: bounds.insets.left,
paddingRight: bounds.insets.right,
}}
>
<Text>Status bar: {bounds.statusBarHeight}</Text>
<Text>Bottom inset: {bounds.insets.bottom}</Text>
<Text>Android nav mode: {bounds.androidNavigationMode}</Text>
<Text>Usable frame height: {bounds.frame.height}</Text>
</View>
);
}Safe Area View
Use ScreenSafeAreaView when you want safe-area padding without writing layout math yourself.
import React from "react";
import { Text } from "react-native";
import { ScreenSafeAreaView } from "react-native-bounds";
export default function Screen() {
return (
<ScreenSafeAreaView edges={["top", "bottom"]} style={{ flex: 1 }}>
<Text>This content avoids the status bar and bottom system area.</Text>
</ScreenSafeAreaView>
);
}Use Without A Component
import { getScreenSafeArea } from "react-native-bounds";
const bounds = getScreenSafeArea();
console.log(bounds.insets);
console.log(bounds.frame);
console.log(bounds.androidNavigationMode);
console.log(bounds.navigationBarHeight);What You Get
| Field | Description |
| --- | --- |
| insets | Top, right, bottom, and left safe-area/system-bar inset values. |
| frame | Usable content frame after subtracting insets. |
| statusBarHeight | Android status bar or iOS top safe-area estimate. |
| navigationBarHeight | Android bottom/side navigation-bar size. |
| androidNavigationMode | "none", "gesture", "three-button", or "unknown". |
| androidNavigationBarPosition | "none", "bottom", "right", "left", or "unknown". |
| hasGestureNavigation | True for iOS home indicator or likely Android gesture navigation. |
| hasNavigationBar | True when Android navigation-bar space is visible. |
| isEstimated | False when Android native insets are used; true for JS estimates. |
Android Navigation Detection
Android can be tricky:
- Some devices show a classic three-button navigation bar.
- Some devices use a small gesture area.
- Some devices report
screenandwindowas the same size even when system bars are visible. - Phones with waterdrop cameras may need display cutout safe insets, not just status-bar height.
react-native-bounds handles this by reading native Android WindowInsets when the native module is linked. That lets it detect real status-bar, display-cutout, and navigation-bar insets.
const bounds = getScreenSafeArea();
if (bounds.androidNavigationMode === "three-button") {
// Keep fixed actions above the Android navigation bar.
}
if (bounds.androidNavigationMode === "gesture") {
// Avoid placing important controls too close to the gesture area.
}
if (bounds.insets.top > 0) {
// Content is below the status bar or waterdrop camera cutout.
}Returned Type
type ScreenSafeArea = {
insets: {
top: number;
right: number;
bottom: number;
left: number;
};
frame: {
x: number;
y: number;
width: number;
height: number;
};
systemBars: {
top: number;
right: number;
bottom: number;
left: number;
};
orientation: "portrait" | "landscape" | "square";
statusBarHeight: number;
navigationBarHeight: number;
androidNavigationMode: "none" | "gesture" | "three-button" | "unknown";
androidNavigationBarPosition: "none" | "bottom" | "right" | "left" | "unknown";
hasNotch: boolean;
hasHomeIndicator: boolean;
hasNavigationBar: boolean;
hasGestureNavigation: boolean;
isEstimated: boolean;
isIOS: boolean;
isAndroid: boolean;
isPortrait: boolean;
isLandscape: boolean;
screenWidth: number;
screenHeight: number;
windowWidth: number;
windowHeight: number;
screenScale: number;
fontScale: number;
};Common Patterns
Floating Bottom Button
const bounds = useScreenSafeArea();
return (
<Pressable
style={{
position: "absolute",
left: 16,
right: 16,
bottom: Math.max(16, bounds.insets.bottom + 12),
}}
>
<Text>Continue</Text>
</Pressable>
);Full Screen Content
const bounds = useScreenSafeArea();
return (
<View
style={{
width: bounds.frame.width,
height: bounds.frame.height,
marginTop: bounds.insets.top,
marginLeft: bounds.insets.left,
}}
/>
);Debug Device Insets
const bounds = useScreenSafeArea();
console.log({
insets: bounds.insets,
statusBarHeight: bounds.statusBarHeight,
navigationBarHeight: bounds.navigationBarHeight,
androidNavigationMode: bounds.androidNavigationMode,
androidNavigationBarPosition: bounds.androidNavigationBarPosition,
isEstimated: bounds.isEstimated,
});Accuracy Notes
Android:
- Uses native
WindowInsetswhen installed in a real Android build. - Includes status bar, navigation bar, and display cutout safe top inset.
- Falls back to
StatusBar.currentHeightand dimension-gap estimates if native insets are unavailable.
iOS:
- Uses JavaScript estimates.
- Detects common modern iPhone notch and Dynamic Island profiles.
- Estimates home indicator and landscape side insets.
For exact native safe-area behavior across every platform, OS version, and edge-to-edge mode, react-native-safe-area-context is still a strong choice. Use react-native-bounds when you want a tiny focused helper with Android navigation detection built in.
API
useScreenSafeArea(): ScreenSafeArea
getScreenSafeArea(): ScreenSafeArea<ScreenSafeAreaView edges={["top", "bottom"]} style={{ flex: 1 }}>
{children}
</ScreenSafeAreaView>License
MIT
