fix(scroll-restoration): save scroll position when navigating with resetScroll=false#6597
fix(scroll-restoration): save scroll position when navigating with resetScroll=false#6597leesb971204 wants to merge 3 commits intoTanStack:mainfrom
Conversation
…setScroll=false Signed-off-by: leesb971204 <leesb971204@gmail.com>
📝 WalkthroughWalkthroughAdds scroll-restoration caching on navigation when Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as Browser Page (Client)
participant Router as Router.commitLocation
participant Cache as scrollRestorationCache (sessionStorage)
participant DOM as DOM / `#sidebar` / window
Browser->>Router: navigate (resetScroll=false)
Router->>DOM: read window.scrollY & element scrollTop (getCssSelector)
Router->>Cache: write per-path scroll state (defaultGetScrollRestorationKey) rgba(100,150,240,0.5)
Note right of Cache: stored in sessionStorage per-path
Browser->>Router: back navigation
Router->>Cache: read stored scroll state rgba(200,120,80,0.5)
Router->>DOM: restore window.scrollY & element scrollTop
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
|
View your CI Pipeline Execution ↗ for commit b49afae
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/router-core/src/router.ts`:
- Around line 2135-2151: The block that runs when next.resetScroll === false and
this.isScrollRestoring only seeds the "window" entry in scrollRestorationCache,
which leaves element-based entries missing/stale; update this code to snapshot
all tracked elements (using the same keying logic as setupScrollRestoration) or
rebuild the entire destination entry instead of only setting 'window'.
Specifically, when computing toKey via this.options.getScrollRestorationKey ||
defaultGetScrollRestorationKey, read the current element selectors used by
setupScrollRestoration and populate keyEntry for each element (e.g., by querying
the elements and storing their scroll positions) so
scrollRestorationCache.set(state => { state[toKey] = { window: ..., [elementId]:
{ scrollX, scrollY }... }; return state; }). Ensure this integrates with
scrollRestorationCache, isScrollRestoring and next.resetScroll semantics and
preserves existing window behavior.
…ositions Signed-off-by: leesb971204 <leesb971204@gmail.com>
3e3b3f4 to
4bc8837
Compare
fixes #6595
Problem Analysis
When navigating A → B → C → B:
resetScroll=false(scroll position maintained)The root cause is that scroll positions are only saved through the
onScrollevent handler. If the user never scrolls on page B, there's no cache entry for B.Solution
Save the current scroll position to the destination route's cache key when navigating with
resetScroll=false. This must happen beforehistory.push/replacebecause the browser resets scroll position after the history change.Why
commitLocation(beforehistory.push)?I evaluated several insertion points:
onRenderedeventwindow.scrollYalready 0onBeforeLoadeventhistory.pushwindow.scrollYalready 0commitLocationbeforehistory.pushThe scroll position must be captured before
history.push/replaceis called, makingcommitLocationthe only viable location.Summary by CodeRabbit
New Features
Bug Fixes
Tests