Packages/@tanstack/virtual-core

Releases of @tanstack/virtual-core

83 stable releases, newest first. Release notes are kept for the last 90 days; older ones link to where they were published.

  1. 3.19.5

    15 October 2026

    Patch Changes

    • fix(virtual-core): keep an instant scroll command clamped at a max the sizer committed outside a row resize

      Before an instant scroll command's write is reported, the browser can clamp it at a smaller scroll max that the sizer moves to without a row resize: an append or prepend, measure(), or a resize the sizer had not committed when the command was written. The virtualizer now also records the max at each commit, so such an event is read as its own clamped write and the command lands. A clamped write reported with isScrolling false is now written again too.

    • fix(virtual-core): keep an instant scroll command when the browser clamps its write before rows grow back

      Rows measured right after an instant scrollToEnd() (or scrollToIndex) can first shrink the sizer below the written position and then grow it again in the same task. The browser clamps the write to the smaller max, and the scroll event reports that position. It was read as the user scrolling away, so the command was cancelled and the list stopped short of the end (a chat opened with estimateSize larger than its rows). The virtualizer now follows the scroll max through those measurements and reads such an event as its own clamped write, so the command retargets and lands at the end.

    • fix(virtual-core): scroll commands and corrections that stalled or were lost

      • On iOS 27 and later a scrollTop write no longer stops a fling but is overridden by it within a frame. A scrollToIndex, scrollToOffset or scrollToEnd issued during a fling now waits for the fling to end instead of being lost. The user taking over before then cancels it: a drag, a second flick, or a finger stopping the fling (iOS reports none of these with touch events while the fling runs). Corrections keep being held through the gesture as on every version.

      • scrollToOffset / scrollBy: a row above the viewport growing after the write's read-back moved the element off the fixed target, and the command kept reconciling until the 5s safety valve. The target now moves with the correction.

      • A prepend (anchorTo: 'end') before the read-back of a scroll command was anchored against the stale offset and written over the command. It is now left to reconcile, like a resize in that window.

      • A scroll event between the prepend's options change and the adapter's commit no longer loses the anchor (one blank frame when the element could not be written by commit time).

      • A command's write clamped by a sizer that shrank below it before the read-back no longer reads as a user scroll; the command reaches its fresh target.

  2. 3.19.4

    13 October 2026

    Patch Changes

    • fix(virtual-core): with useAnimationFrameWithResizeObserver, request frames from the scroll element's window instead of the global one, and cancel frames still queued on cleanup, so a list rendered into another window does not stall while the opener is minimized or occluded

  3. 3.19.3

    13 October 2026

    Patch Changes

    • refactor(virtual-core): simplify the scroll-correction state: a scroll write is tracked until its read-back as one record, the iOS touch gesture as one record, the pending prepend anchor as a tagged record, and every scroll command starts through one entry point (no behaviour change, with two exceptions: a second touchend/touchcancel inside the post-touch grace window now restarts the window instead of leaving the first timer to end it early, and after the scroll element is swapped or the virtualizer disabled, a write to the old element is no longer matched to the new element's first scroll report). scrollAdjustments becomes a read-only getter with the same value (assigning to it is no longer supported).

  4. 3.19.2

    12 October 2026

    Patch Changes

    • fix(virtual-core): treat iOS touchcancel like touchend so interrupted gestures cannot leave touch state stuck and keep scroll anchoring suppressed

    • refactor(virtual-core): track an in-flight scroll command's lifecycle as one phase instead of several flags (no behaviour change)

  5. 3.19.1

    12 October 2026

    Patch Changes

    • fix(virtual-core): let a user scroll end a non-smooth scrollToIndex before reconcile has seen it land, so a later measurement no longer pulls the user back to the old target

    • fix(virtual-core): leave resizes measured before a scroll command's write is read back to reconcile, so an upward scrollToIndex no longer jumps back and stalls until the safety valve, and build scrollBy on a just-written offset

  6. 3.19.0

    11 October 2026

    Minor Changes

    • fix(virtual-core): keep lanes aligned after changing lanes with measureElement

      • overscan now counts whole rows when lanes > 1, so every lane renders (and measures) the same number of extra items. This renders more items than before: lanes: 4, overscan: 2 now adds 8 items on each side instead of 2. Range gains an optional lanes field that defaultRangeExtractor reads; a custom rangeExtractor gets row overscan only if it delegates to defaultRangeExtractor.

      • A ResizeObserver callback now measures all of its entries before notifying, so a synchronous re-render can no longer unmount part of a row before it is measured.

  7. 3.18.0

    9 October 2026

    Minor Changes

    • feat(virtual-core): add cancelScroll() to stop an in-flight scrollToIndex / scrollToOffset / scrollBy / scrollToEnd from correcting toward its target, so a user gesture can take over the viewport

    Patch Changes

    • Fix scrollToIndex(last, { align: 'end' }) overshooting the last item by paddingEnd; it now respects scrollPaddingEnd like other end-aligned items. To scroll to the very bottom including paddingEnd, use scrollToEnd().

  8. 3.17.11

    14 September 2026

    Patch Changes

    • Read the current scroll offset when the debounced scroll-end fallback fires so measurement adjustments made since the last browser scroll event are not overwritten by stale state.

    • Keep a travelling smooth scrollToIndex alive when content is prepended. With anchorTo: 'end', the prepend anchor sync wrote scrollTop instantly, which cancelled the browser's smooth animation and left the scroll stranded partway; Chromium drops a smooth request re-issued right after such a cancel, so it could not be resumed. The sync is now skipped while a smooth programmatic scroll is still in flight, and the animation continues to its recomputed target. A smooth scroll that has already landed still receives the anchor sync.

  9. 3.17.10

    11 September 2026

    Patch Changes

    • Keep an end-pinned virtualizer following appended items when older items are trimmed in the same update and the item count does not increase. Recognize ordered, overlapping windows while preserving reading anchors for users who have scrolled away from the end.

      Preserve item keys in the lazy measurement cache so a stable getItemKey callback reading mutable data cannot change the identity of previously measured rows.

  10. 3.17.9

    7 September 2026

    Patch Changes

    • Recover the bottom pin when the browser clamps an end-anchored scroll compensation write. resizeItem compensates a size change by writing scrollTop before the consumer has committed the new total size, so when the grown item does not itself extend the scroll range the browser clamps the write to the old maximum and the viewport is left short of the end with no scroll event to correct it. Two cases hit this: paddingEnd > 0 with a growing last item, where the overflowing item only extends scrollHeight to its own end and the clamp lands exactly paddingEnd short (#1258); and a row above the last one growing while the last row keeps its size, under directDomUpdates (#1266). A compensation write whose target exceeds the scroll maximum at write time is now recorded as clamped and re-issued once the sizer has grown — right after notify for consumers that size the container synchronously in onChange, and from _willUpdate for consumers that size it during a render. The clamped read-back keeps the retry pending; any other scroll event cancels it, so a user reading history is never yanked.

  11. 3.17.8

    18 August 2026

    Patch Changes

    • Cancel the pending isScrolling reset when a scroll observer is torn down, and reset isScrolling and scrollDirection in cleanup() so they don't stay stuck after the scroll element changes or is removed.

    • Ignore connected measurement nodes whose indexes are outside the current item count.

  12. 3.17.7

    28 July 2026

    Patch Changes

    • Fix a one-frame viewport jump when above-viewport rows resize while scrolling up (#1227). resizeItem writes scrollTop synchronously inside the ResizeObserver callback to compensate for the size change, but then notified asynchronously — so the browser could paint a frame with the new scrollTop and the old item transforms, making the content jerk by the resize delta and snap back. When a compensation actually moves the scroll position, resizeItem now notifies synchronously so the transform commit lands in the same paint as the scroll write. Resizes that don't move the scroll position (below-fold measurements, iOS-deferred adjustments) keep the cheaper async notify.

  13. 3.17.6

    22 July 2026

    Patch Changes

    • Stop the default scroll-adjustment heuristic from drifting the viewport when a viewport-spanning item grows. Previously any item whose top sat above the fold (itemStart < scrollOffset) had its size delta compensated on every re-measure — including a streaming chat message that spans the fold and grows at its bottom, dragging scrollTop downward token by token (#1218). Re-measurements now only compensate items that are entirely above the fold (itemStart + itemSize <= scrollOffset); growth below the anchor point leaves the scroll position untouched. First measurements (estimate→actual) still compensate any above-fold item, and a custom shouldAdjustScrollPositionOnItemSizeChange still overrides the default.

  14. 3.17.5

    20 July 2026

    Patch Changes

    • Clamp the tracked scrollOffset at 0 when applying end-anchor measurement compensation and when re-anchoring in setOptions. Previously, with anchorTo: 'end' and content shorter than the viewport, items measuring smaller than their estimates drove the tracked offset negative with no scroll event to ever correct it — getDistanceFromEnd() reported a permanent phantom distance and iOS deferred measurement corrections stayed wedged forever.

    • Stop iOS-deferred scroll adjustments from replaying stale deltas after the position is already correct (#1233). On iOS WebKit the end-anchored virtualizer defers scroll compensation while the scroller is live and replays it once settled, but two cases replayed a delta whose premise no longer held:

      • Absolute scroll commands (scrollToOffset / scrollToIndex / scrollToEnd) derive their target from current measurements, so a pending deferred delta is already stale — it now invalidates the deferral instead of letting it replay and shift the list off the just-established position. Relative commands (scrollBy) keep the deferral.

      • At the end clamp with anchorTo: 'end', a row above the viewport re-measuring smaller lets the browser clamp scrollTop onto the new bottom (already the correct position); the flush now drops the stale negative compensation instead of replaying it and lifting the view off the bottom. Positive deltas still replay, since content growth above does not clamp.

  15. 3.17.4

    12 July 2026
  16. 3.17.3

    30 June 2026
  17. 3.17.2

    26 June 2026
  18. 3.17.1

    15 June 2026
  19. 3.17.0

    2 June 2026
  20. 3.16.1

    1 June 2026
  21. 3.16.0

    25 May 2026
  22. 3.15.0

    20 May 2026
  23. 3.14.0

    17 April 2026
  24. 3.13.23

    16 March 2026
  25. 3.13.22

    12 March 2026
  26. 3.13.21

    6 March 2026
  27. 3.13.20

    5 March 2026
  28. 3.13.19

    23 February 2026
  29. 3.13.18

    7 January 2026
  30. 3.13.17

    6 January 2026
  31. 3.13.16

    3 January 2026
  32. 3.13.15

    3 January 2026
  33. 3.13.14

    30 December 2025
  34. 3.13.13

    8 December 2025
  35. 3.13.12

    27 June 2025
  36. 3.13.11

    23 June 2025
  37. 3.13.10

    9 June 2025
  38. 3.13.9

    20 May 2025
  39. 3.13.8

    5 May 2025
  40. 3.13.7

    5 May 2025
  41. 3.13.6

    31 March 2025
  42. 3.13.5

    24 March 2025
  43. 3.13.4

    13 March 2025
  44. 3.13.3

    12 March 2025
  45. 3.13.2

    25 February 2025
  46. 3.13.1

    25 February 2025
  47. 3.13.0

    7 February 2025
  48. 3.12.1

    7 February 2025
  49. 3.12.0

    3 February 2025
  50. 3.11.3

    27 January 2025