React: Conditionally rendering causes scroll element to scroll to top
Describe the bug
When a 2nd conditionally rendered virtual list is rendered, the page automatically scrolls to the top
Your minimal, reproducible example
https://codesandbox.io/p/devbox/cranky-fermat-vzkmd3
Steps to reproduce
Scroll to bottom and click the Render More button. Once clicked the 2nd virtualized list will render and the page will scroll to the top
Expected behavior
When the 2nd virtualized list is rendered, the page should not scroll to the top.
How often does this bug happen?
Every time
Screenshots or Videos
https://github.com/user-attachments/assets/4309df5d-4e1c-4900-bf5a-aced7b66757a
Platform
- OS: macOS
- Browser: Chrome 137
tanstack-virtual version
3.13.12
TypeScript version
5.8.3
Additional context
No response
Terms & Code of Conduct
- [x] I agree to follow this project's Code of Conduct
- [x] I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
Analysis so far
-
react virtual is triggering
_willUpdatewhen the new virtual instance is rendered -
_willUpdateenters theif (this.scrollElement !== scrollElement)condition. This is becausethis.scrollElementis null because it's a new instance - Inside this condition, we trigger
this._scrollToOffset.this.getScrollOffsetreturns 0 -
this.getScrollOffsetreturns 0 since this is a new instance and we do not have theinitialOffsetoption set. - Which means react-virtual scrolls to the top of the scrollElement on mount
Yeah, that’s true, setting initialOffset is the way to go right now. Though 🤔 it might be interesting if the virtualizer could read the current scroll offset automatically from the scroll element as a default fallback. Could be worth exploring!
Setting initialOffset on useVirtualizer doesn't solve the reported bug. When the virtual list is rendered, the scroll container is scrolled to the top.
@bkdiehl Setting initialOffset should solve this, it ensures the scroll container starts at the correct position on first render. https://stackblitz.com/edit/vitejs-vite-h9bxrw4k
if you’re still seeing the scroll jump to the top, could you share a minimal repro where initialOffset doesn’t work?
@piecyk You're right. Thank you for the example. It wasn't clear to me what the value for initialOffset was supposed to be. I was assigning the same value that I was passing to scrollMargin. It would be nice if the docs could better reflect how this should be used. Useful for much more than just SSR purposes.
@bkdiehl You’re totally right, the docs and examples definitely need some love. Happy to accept any PRs
Just to clarify:
- scrollMargin is the offset where the list starts inside the scroll container.
- initialOffset is the position where the list is scrolled to on initial render.
They often work together, but they serve different purposes. Glad the example helped!
Thanks for the workaround @piecyk 🙏 I've made a PR to update the docs on this: https://github.com/TanStack/virtual/pull/1045