Version
v5
Reanimated Version
v3
Gesture Handler Version
v2
Platforms
iOS
What happened?
When a React Navigation stack screen containing a presented BottomSheetModal is popped without calling dismiss() first, the modal's portal entry is never removed from the @gorhom/portal reducer state. The PortalHost continues rendering the stale BottomSheet tree — including its BackdropComponent with
StyleSheet.absoluteFillObject and pointerEvents="auto" — blocking all touches app-wide.
Root cause in source: handlePortalOnUnmount in BottomSheetModal.tsx (~line 311) ignores the removePortal callback passed to it by Portal's unmount effect. Instead it tries bottomSheetRef.current?.close() and relies on the animation completing to eventually call unmount() → unmountPortal(). If bottomSheetRef.current is
already null (React tore down the inner BottomSheet before the Portal cleanup fires), close() never runs and the portal entry is never removed.
Suggested fix: handlePortalOnUnmount should accept and use the removePortal callback as a fallback when bottomSheetRef.current is null.
Workaround:
useEffect(() => {
const ref = bottomSheetRef.current;
return () => { ref?.dismiss(); };
}, []);
Reproduction steps
- Wrap your app in
BottomSheetModalProvider
- On a stack screen, render a
BottomSheetModal and call present()
- Pop the screen (navigate back) without calling
dismiss() first
- All touches on any screen are now blocked by the invisible orphaned backdrop
Reproduction sample
https://snack.expo.dev/@dcdevteam/bottom-sheet---issue-reproduction-template
Relevant log output
Version
v5
Reanimated Version
v3
Gesture Handler Version
v2
Platforms
iOS
What happened?
When a React Navigation stack screen containing a presented
BottomSheetModalis popped without callingdismiss()first, the modal's portal entry is never removed from the@gorhom/portalreducer state. ThePortalHostcontinues rendering the staleBottomSheettree — including itsBackdropComponentwithStyleSheet.absoluteFillObjectandpointerEvents="auto"— blocking all touches app-wide.Root cause in source:
handlePortalOnUnmountinBottomSheetModal.tsx(~line 311) ignores theremovePortalcallback passed to it by Portal's unmount effect. Instead it triesbottomSheetRef.current?.close()and relies on the animation completing to eventually callunmount()→unmountPortal(). IfbottomSheetRef.currentisalready null (React tore down the inner BottomSheet before the Portal cleanup fires),
close()never runs and the portal entry is never removed.Suggested fix:
handlePortalOnUnmountshould accept and use theremovePortalcallback as a fallback whenbottomSheetRef.currentis null.Workaround:
useEffect(() => {
const ref = bottomSheetRef.current;
return () => { ref?.dismiss(); };
}, []);
Reproduction steps
BottomSheetModalProviderBottomSheetModaland callpresent()dismiss()firstReproduction sample
https://snack.expo.dev/@dcdevteam/bottom-sheet---issue-reproduction-template
Relevant log output