Fixes an Android bug where a closed BottomSheet with a backdrop can block all touch events on the underlying screen after a cold start.#2706
Open
kanav22 wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes an Android bug where a closed BottomSheet with a backdrop can block all touch events on the underlying screen after a cold start.
Closes #2680
Problem
When a screen mounts a closed bottom sheet (index={-1}) with a BottomSheetBackdrop, some Android devices stop receiving scroll and button presses on the content behind the sheet. The UI renders correctly, but touches appear to be swallowed. Backgrounding the app and returning restores interaction without navigating away.
Reported on devices including Samsung (Android 14) and Xiaomi (Android 11).
Root cause
Two independent issues in BottomSheetBackdrop:
Mount race condition
pointerEvents was always initialized to 'auto' when enableTouchThrough is false. useAnimatedReaction can fire before the mount useEffect sets isMounted.current = true. Because handleContainerTouchability only updates state when mounted, that first update is silently skipped and the invisible backdrop keeps intercepting touches.
Floating-point animatedIndex
On some devices, animatedIndex settles at -0.999… instead of exactly -1. With disappearsOnIndex={-1}, the check animatedIndex.value <= disappearsOnIndex evaluates to false, so pointerEvents never switches to 'none'.
Solution
Derive the initial pointerEvents value from the current animatedIndex instead of defaulting to 'auto'
Sync pointerEvents on mount to recover from the race where the animated reaction fires before the component is mounted
Use an epsilon-based closed-state check (index <= disappearsOnIndex + 0.01) so near-closed values like -0.9999 are treated as closed without affecting partially open positions during animations
How to reproduce (before fix)
Use @gorhom/bottom-sheet@5.2.14
Render a screen with scrollable content and a closed bottom sheet (index={-1})
Add a backdrop with appearsOnIndex={0} and disappearsOnIndex={-1}
Cold start on an affected Android device
Try scrolling or pressing buttons behind the sheet
Observe that touches are blocked until the app is backgrounded and resumed
<BottomSheet
ref={sheetRef}
index={-1}
enableDynamicSizing
enablePanDownToClose
backdropComponent={renderBackdrop}
...
Test plan
yarn typescript
passes
biome check
passes on the changed file
Cold-start repro on physical Android device (Samsung / Xiaomi class devices)
Verify backdrop still captures presses when the sheet is open
Verify
enableTouchThrough
behavior is unchanged
Verify opening/closing the sheet still works as expected
Risks / notes
The epsilon value (0.01) is intentionally small so mid-animation indices (e.g. -0.3) are not incorrectly treated as closed
This is a targeted change to BottomSheetBackdrop.tsx only; no API changes
Related community workaround was setting disappearsOnIndex={-0.5} — this fix addresses the underlying comparison issue without requiring consumers to change their config