Describe the bug
With anchorTo: 'end' and directDomUpdates: true, growing an earlier row can leave the viewport above the bottom even though it was previously pinned. The gap persists when the last row keeps its size.
The standalone reproduction uses eight messages with exact initial size estimates. The last row is 300px tall, matching the viewport, and only the preceding row grows by 24px. The browser reports a 24px bottom gap after the resize.
Your minimal, reproducible example
Run the live reproduction
Source and local run instructions
The example uses published npm packages: @tanstack/react-virtual@3.14.10, @tanstack/virtual-core@3.17.8, and React 19.2.8. It sets useFlushSync: false and uses native ResizeObserver measurements. CSS scroll anchoring is disabled with overflow-anchor: none to isolate the virtualizer's adjustment.
Steps to reproduce
- Open the preview and wait for Actual bottom gap: 0 px.
- Click Grow previous message by 24 px once.
- Observe Actual bottom gap: 24 px. The last row's bottom is now below the viewport.
- Reload to repeat.
Measured from the actual scroll element:
| DOM value |
Before |
After |
scrollHeight |
650 |
674 |
clientHeight |
300 |
300 |
scrollTop |
350 |
350 |
scrollHeight - clientHeight - scrollTop |
0 |
24 |
The diagnostics are rendered by a separate sibling component, so updating them does not rerender the virtualized list.
Expected behavior
The viewport remains pinned: scrollTop advances to 374 and the bottom gap stays at 0px when the preceding row grows.
How often does this bug happen?
Every time with the steps above.
Screenshots or Videos

Platform
- macOS 26.5.2
- Chromium 141.0.7390.37
tanstack-virtual version
@tanstack/react-virtual@3.14.10 / @tanstack/virtual-core@3.17.8
TypeScript version
Not applicable; the reproduction uses JavaScript/JSX.
Additional context
resizeItem updates the measurements and applies its scroll adjustment before onChange updates the React adapter's direct DOM size container. The browser clamps the adjustment against the old scrollHeight; the container grows afterwards, leaving the actual DOM offset behind. Keeping the last row unchanged makes the gap persist.
Proposed fix: #1265. It applies the adapter's existing applyContainerSize before delegating to scrollToFn, with a browser regression test. This follows the ordering principle used for prepend synchronization in #1237, and covers the resize path. This reproduction does not use paddingEnd, unlike #1258.
Terms & Code of Conduct
Describe the bug
With
anchorTo: 'end'anddirectDomUpdates: true, growing an earlier row can leave the viewport above the bottom even though it was previously pinned. The gap persists when the last row keeps its size.The standalone reproduction uses eight messages with exact initial size estimates. The last row is 300px tall, matching the viewport, and only the preceding row grows by 24px. The browser reports a 24px bottom gap after the resize.
Your minimal, reproducible example
Run the live reproduction
Source and local run instructions
The example uses published npm packages:
@tanstack/react-virtual@3.14.10,@tanstack/virtual-core@3.17.8, and React 19.2.8. It setsuseFlushSync: falseand uses native ResizeObserver measurements. CSS scroll anchoring is disabled withoverflow-anchor: noneto isolate the virtualizer's adjustment.Steps to reproduce
Measured from the actual scroll element:
scrollHeightclientHeightscrollTopscrollHeight - clientHeight - scrollTopThe diagnostics are rendered by a separate sibling component, so updating them does not rerender the virtualized list.
Expected behavior
The viewport remains pinned:
scrollTopadvances to 374 and the bottom gap stays at 0px when the preceding row grows.How often does this bug happen?
Every time with the steps above.
Screenshots or Videos
Platform
tanstack-virtual version
@tanstack/react-virtual@3.14.10/@tanstack/virtual-core@3.17.8TypeScript version
Not applicable; the reproduction uses JavaScript/JSX.
Additional context
resizeItemupdates the measurements and applies its scroll adjustment beforeonChangeupdates the React adapter's direct DOM size container. The browser clamps the adjustment against the oldscrollHeight; the container grows afterwards, leaving the actual DOM offset behind. Keeping the last row unchanged makes the gap persist.Proposed fix: #1265. It applies the adapter's existing
applyContainerSizebefore delegating toscrollToFn, with a browser regression test. This follows the ordering principle used for prepend synchronization in #1237, and covers the resize path. This reproduction does not usepaddingEnd, unlike #1258.Terms & Code of Conduct