Provider-scoped display divisions and occlusions for React Native's New Architecture.
- React Native 0.80 or newer with the New Architecture (Fabric)
- iOS 27.1 SDK and runtime for UIKit reserved regions; older SDKs compile out observation and older runtimes report an empty list
- Android 7.0 (API 24) or newer; folding features require a device supported by Jetpack WindowManager
The example app uses React Native 0.88.0-rc.1.
Its iOS target adopts UISceneDelegate because the RC template currently crashes on iOS 27 without it (React Native issue #58606).
npm install react-native-reserved-regionsOn iOS, install pods in your app's ios directory. Android links automatically through React Native autolinking.
import { View } from 'react-native';
import { ReservedRegionsProvider, useReservedRegions } from 'react-native-reserved-regions';
function Screen() {
const fold = useReservedRegions().find(
(region) => region.kind === 'division' && region.frame.height > region.frame.width,
);
if (!fold) return <Detail />;
return (
<View style={{ flex: 1, flexDirection: 'row' }}>
<View style={{ width: fold.frame.x }}>
<List />
</View>
<View style={{ width: fold.frame.width }} />
<View style={{ flex: 1 }}>
<Detail />
</View>
</View>
);
}
export default function App() {
return (
<ReservedRegionsProvider style={{ flex: 1 }}>
<Screen />
</ReservedRegionsProvider>
);
}useReservedRegions() always returns an array, initially []. useReservedRegionsReady() is initially false and becomes true with the first measurement, including an empty result. It stays true for that provider’s lifetime. Unsupported platforms report a known empty result; readiness does not indicate hardware support or guarantee first-frame timing. Both hooks must be called beneath a ReservedRegionsProvider. Each region's frame uses logical points relative to that provider's top-left corner. A nested provider establishes its own coordinate space. The provider accepts standard React Native View props and should cover the content whose reserved regions you want to inspect.
The public type is a tagged union:
type ReservedRegion =
| {
kind: 'division';
frame: { x: number; y: number; width: number; height: number };
occludesContent: boolean;
}
| {
kind: 'occlusion';
frame: { x: number; y: number; width: number; height: number };
};A division splits the available display. occludesContent tells you whether content under that division is hidden. An occlusion is an area where content is hidden. On iOS, division regions currently report occludesContent: false. The TypeScript declarations in src/index.tsx document every field.
A reserved region needs a coordinate space: the same fold has different local
coordinates in a full-screen view and an inset panel. ReservedRegionsProvider
renders the native view that defines those bounds and shares its measurements
with descendants. useReservedRegions() reads the nearest provider, so several
consumers can use the same measurements without each adding a native view. Place
a provider around each area that needs its own coordinate space; it can replace
an existing container View.
react-native-hinges exposes a hook without a provider because posture and angle do not depend on a child view's position or size. It observes the existing React root's hierarchy/window. Use both libraries when layout and animation need those separate inputs.
- iOS queries UIKit's active
UIViewreserved division and occlusion regions on the provider view. Typed UIKit calls are guarded by the SDK version and runtime availability. Building with an SDK older than iOS 27.1 compiles out this feature. Apple's reserved regions overview - Android observes Jetpack WindowManager
FoldingFeaturevalues and Android display cutout rectangles. A separating or fully occluding fold becomes a division;OcclusionType.FULLsetsoccludesContenttotrue. Display cutouts become occlusions. FoldingFeature reference, WindowInsets reference
The library reports geometry and does not reposition content. Normal safe area insets, system bars, and keyboard insets remain separate concerns.
The first measurement requests synchronous delivery; later changes are regular events. Android measures after Fabric mounting and again on its own relayout, fold changes and window inset changes; scrolling or moving an ancestor does not trigger a measurement. On iOS, same-frame delivery requires React Native #58530; see measurement timing. Readiness indicates a completed measurement, not a universal first-frame guarantee.
The performance guide explains provider placement and optional readiness gating.
pnpm install --frozen-lockfile
pnpm run format:check
pnpm run lint
pnpm run typecheck
pnpm test
pnpm run build
pnpm run docs:buildThe example includes full-screen, inset and content-box providers with
react-native-safe-area-context values and overlays for comparison.
See the development workflow for native runs,
the docs website for local previews, and
the release process for publishing.
MIT