Skip to content

[React] directDomUpdates loses end anchoring when an earlier row grows #1266

Description

@tigerBeA

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

  1. Open the preview and wait for Actual bottom gap: 0 px.
  2. Click Grow previous message by 24 px once.
  3. Observe Actual bottom gap: 24 px. The last row's bottom is now below the viewport.
  4. 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

After growing the previous row: actual bottom gap is 24px

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

  • I agree to follow this project's Code of Conduct.
  • I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions