fix(scrollable): preserve scroll position when keyboard dismisses#2676
Open
ronnymajani wants to merge 1 commit into
Open
fix(scrollable): preserve scroll position when keyboard dismisses#2676ronnymajani wants to merge 1 commit into
ronnymajani wants to merge 1 commit into
Conversation
When the keyboard dismisses, the inner scroll jumps back to offset 0 even though the user had scrolled. During the keyboard-down animation, the sheet `position` is between `extendedPositionWithKeyboard` and `extendedPosition`, so `animatedSheetState` falls through to `OPENED` (it only reports `EXTENDED` when `position` exactly matches `extendedPosition`). `useScrollable` then returns `LOCKED`, and `handleOnScroll` forces `scrollTo(0, 0)` because `shouldLockInitialPosition` was cleared earlier when the sheet was `EXTENDED` at drag start. The existing unlock condition only covers `KEYBOARD_STATUS.SHOWN`. Extend it to also cover animations whose `source` is `ANIMATION_SOURCE.KEYBOARD`, which handles the dismiss path where the keyboard is already `HIDDEN` but the sheet is still animating.
|
Hi, I was able to see the issue, I can confirm that it's there. Here's a recording previewing it: Screen.Recording.2026-05-21.at.15.31.03.mov |
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.
Motivation
When a
BottomSheetcontains a scrollable and aTextInput, the following sequence fails:TextInputfurther down — keyboard appears, sheet animates up (interactive keyboard behavior).The user's scroll position is lost on every keyboard dismiss, which makes long forms inside a sheet effectively unusable.
Root cause
The relevant code in
useScrollable.ts:This unlocks the scrollable during keyboard-show animations so the scroll position is preserved while the sheet translates. But it only matches
KEYBOARD_STATUS.SHOWN. During the dismiss animation, the keyboard status has already flipped toHIDDEN, while the sheet is still animating back fromextendedPositionWithKeyboardtoextendedPosition. So this branch doesn't apply on the way down.During that dismiss window:
animatedPositionis betweenextendedPositionWithKeyboardandextendedPosition.animatedSheetState(inBottomSheet.tsx) checks foranimatedPosition.value === extendedPosition(exact equality) — false during animation.isInTemporaryPositionwas just flipped tofalseingetEvaluatedPosition.SHEET_STATE.OPENED.With sheet state
OPENEDand the keyboard branch not matching,useScrollablereturnsLOCKED.handleOnScroll(inuseScrollEventsHandlersDefault.ts) then firesscrollTo(scrollableRef, 0, lockPosition, false). Because the user started dragging while the sheet wasEXTENDED,shouldLockInitialPositionisfalse, solockPosition = 0— instant jump to top.The bug only manifests because
OPENEDis reached mid-animation. Once the animation completes andposition === extendedPositionagain,animatedSheetStateflips back toEXTENDEDand unlocks the scroll — too late, thescrollTo(0)has already fired.What this PR does
Extends the unlock condition to also cover keyboard-dismiss animations by checking the animation's
source:animationState.source === ANIMATION_SOURCE.KEYBOARDis true for both the show and dismiss animations triggered by the keyboard state machine, so it cleanly covers the missing case without weakening the existing one.Files changed
src/hooks/useScrollable.ts— extended unlock condition; added anANIMATION_SOURCEimport.No API changes, no type changes.
Verification
yarn typescript— cleanyarn lint --error-on-warnings src/hooks/useScrollable.ts— cleanBottomSheetScrollViewcontaining several inputs: scroll position is now preserved across keyboard show and dismiss. Behavior unchanged for non-keyboard animations and for sheets without keyboard interactions.Notes
This is a pure scroll-preservation fix and is independent of #2675 (which fixes a separate Android-only scroll-cancellation bug on first sheet open). Either can land independently.