OverlayProvider
The one teleport host every dialog, drawer, popover, tooltip, toast and sheet draws into, and the z-order between them.
Installation
Overlay ships with the library — install it once, then import:
import { Overlay } from "@delacour/react-native-ui/overlay";Or copy the source into your project, to own and edit it:
bunx delacour@latest add overlayUsage
import "@/styles/global.css";
import { BottomSheetProvider } from "@/components/ui/bottom-sheet";
import { OverlayProvider } from "@/components/ui/overlay";
import { DelacourProvider } from "@/components/ui/provider";
import { Stack } from "expo-router";
export default function RootLayout() {
return (
<DelacourProvider>
<OverlayProvider>
<BottomSheetProvider>
<Stack screenOptions={{ headerShown: false }} />
</BottomSheetProvider>
</OverlayProvider>
</DelacourProvider>
);
}Mount it once, inside DelacourProvider and around the
navigator. DelacourProvider cannot mount it for you: react-native-teleport is an optional peer,
and an app with no overlay never has to build it.
What it does
- One teleport host for everything. Overlays and bottom sheets all draw into the same
"root"host over the navigator.OverlayProviderandBottomSheetProvidereach mount teleport's provider only when the other has not, so either order works — and there is never a second host with the same name. - One z-order. Every overlay draws above every sheet; a popover draws above the dialog that opened it; a toast draws above everything. Within a layer the latest open is on top.
- One back button. On Android, back closes the topmost dialog, drawer or popover and nothing under it. A toast never takes it.
Without the provider an overlay still renders, inline where it is written, and warns once in
development — but it can be clipped by any ancestor with overflow: hidden, and it draws under
the navigator's header.
Building your own overlay
The parts the library's overlays are drawn with are exported too:
import { Overlay, useOverlayBackHandler, useOverlayPresence } from "@/components/ui/overlay";
import { useId } from "react";
function Sheetlet({ isOpen, onClose, children }) {
const id = useId();
const { isPresent, progress } = useOverlayPresence({ isOpen });
useOverlayBackHandler({ id, isEnabled: isPresent, onBack: onClose });
if (!isPresent) return null;
return (
<Overlay.Portal id={id} layer="modal">
<Overlay.Scrim progress={progress} onDismiss={onClose} />
{children}
</Overlay.Portal>
);
}useOverlayPresence keeps the overlay mounted until its exit animation finishes and drives
progress from 0 to 1 and back; under reduce motion it still fades, and isReduced tells you to
drop your transforms.
API Reference
Prop
Type