Components

Overlays

Use screen overlays as persistent, stack-relative UI with their own sparse transition order.

Mental Model

An overlay is a floating layer owned by one screen in a navigator. It renders above that navigator's screens and stays mounted while its owner remains in the stack.

Configure it with the overlay and overlayShown screen options:

TSX

1<Stack.Screen
2 name="Home"
3 component={HomeScreen}
4 options={{
5 overlay: HomeOverlay,
6 overlayShown: true,
7 }}
8/>

Overlays are scoped to their own navigator. They do not float into a parent, child, or sibling navigator.

The Overlay Stack

Screens and overlays have separate adjacency. If [] means that a screen owns an overlay, this screen stack:

TEXT

1A[] -> B -> C[] -> D -> E[]

produces this overlay stack:

TEXT

1A[] -> C[] -> E[]

Pushing B leaves A floating in place. Pushing C mounts C above A, and pushing E mounts E above C. Screens without overlays do not create gaps in the overlay transition order.

An overlay mounts once and keeps its component state until its owner leaves the navigation stack or overlayShown becomes false. The top overlay accepts touches. The overlay directly below it can remain visible for the transition, but it is inert; older overlays stay mounted and inactive.

Basic Example

TSX

1<Stack.Navigator>
2 <Stack.Screen
3 name="A"
4 component={ScreenA}
5 options={{ overlay: OverlayA }}
6 />
7 <Stack.Screen name="B" component={ScreenB} />
8 <Stack.Screen
9 name="C"
10 component={ScreenC}
11 options={{ overlay: OverlayC }}
12 />
13</Stack.Navigator>

Here, OverlayA remains above B. When C is pushed, OverlayC becomes active above OverlayA.

Animate the Overlay Stack

overlay is a reserved screenStyleInterpolator slot. The destination screen's interpolator drives the current adjacent overlay pair.

TSX

1screenStyleInterpolator: ({
2 progress,
3 layouts: {
4 screen: { width },
5 },
6}) => {
7 "worklet";
8
9 return {
10 content: {
11 style: {
12 transform: [
13 {
14 translateX: interpolate(
15 progress,
16 [0, 1, 2],
17 [width, 0, -width * 0.3],
18 "clamp",
19 ),
20 },
21 ],
22 },
23 },
24 overlay: {
25 style: {
26 transform: [
27 {
28 translateX: interpolate(
29 progress,
30 [0, 1, 2],
31 [width, 0, -width],
32 "clamp",
33 ),
34 },
35 ],
36 },
37 },
38 };
39}

In A[] -> B -> C[], the overlay slot from C animates A out and C in. B is part of the screen stack, but not the overlay stack.

A screen does not need to own an overlay to drive the latest one. In A[] -> B, an overlay slot returned by B styles A. If B does not return the slot, A is left alone.

Do not use overlay as a custom styleId. It is a non-inheriting layer slot, like content and backdrop.

Owner State and Focused State

An overlay can outlive the moment when its owner was focused, so its props separate stable owner information from changing navigator information.

PropPurpose
routeRoute that owns the overlay
indexOwner route index
focusedRouteCurrently presented route in this navigator
focusedIndexCurrently presented route index
routesAll routes in this navigator's stack
metaMetadata from the focused screen options
optionsTransition options from the focused screen
navigationNavigation object for the overlay owner's navigator
progressStack progress relative to the overlay owner

An undecided interactive dismissal keeps the current route focused. Once the dismissal commits, focusedRoute, focusedIndex, meta, and options switch to the screen underneath while the closing screen finishes animating. A cancelled gesture leaves them unchanged.

Animation and Style IDs Inside an Overlay

The floating host reuses the stores created by the owner screen. It does not build a second descriptor, options, gesture, or animation provider tree.

That keeps these APIs scoped to the route that owns the overlay:

TSX

1function HomeOverlay() {
2 const animation = useScreenAnimation();
3
4 return (
5 <Transition.View styleId="floating-actions">
6 <Actions progress={animation} />
7 </Transition.View>
8 );
9}

Use the reserved interpolator overlay slot when the screen transition should move the overlay layer itself. Use useScreenAnimation() or a custom styleId when elements inside the overlay need their own motion.