unstale

npm / @tanstack/virtual-core

@tanstack/virtual-core

What changed in @tanstack/virtual-core 3, from its official release notes, upgrade guides and advisories. Sources checked 2026-11-13.

4 breaking1 deprecations12 new APIs and options5 performance60 fixes and other

See which of these apply to your code, ranked, in your agent:

npx @unstale/cli init

@unstale/cli 0.3.0 on npm

@tanstack/virtual-core 382 changes

Breaking changes 4

  • scrollAdjustments is now a read-only getter with the same value; assigning to it is no longer supported.

    3.19.3release notes

  • When lanes > 1, overscan counts whole rows, rendering the same number of extra items in every lane; custom rangeExtractors get row overscan only if they delegate to defaultRangeExtractor.

    3.19.0release notes

  • Changes to the gap option now invalidate measurements.

    3.17.4release notes

  • Reverts notifying the framework when the count changes.

    3.13.18release notes

Deprecations 1

  • Deprecated because corrections are folded into scrollOffset immediately; read scrollOffset alone. The getter remains and scrollAdjustments is always 0.

    3.19.5release notes

New APIs and options 12

  • Range gains an optional lanes field, which defaultRangeExtractor reads.

    3.19.0release notes

  • Adds a method to stop an in-flight scroll operation from correcting toward its target, allowing a user gesture to take over the viewport.

    3.18.0release notes

  • Adds an option to skip DOM measurement when the list is hidden; the default measureElement returns the cached size or estimateSize fallback instead of reading the DOM.

    3.17.0release notes

  • Adds end-anchored virtualization with anchorTo: 'end', keeping the visible item stable when older items are prepended and an end-pinned viewport pinned when the last item grows. Start-anchored behavior remains the default.

    3.16.0release notes

  • Adds an option to scroll new items into view only when the viewport was already at the end.

    3.16.0release notes

  • Adds a helper for chat-style integrations to get the distance from the end.

    3.16.0release notes

  • Adds a helper for chat-style integrations to determine whether the viewport is at the end.

    3.16.0release notes

  • Adds a scroll-end threshold for chat-style integrations.

    3.16.0release notes

  • Adds a helper for scrolling to the end in chat-style integrations.

    3.16.0release notes

  • Adds an instance method that returns currently measured items as VirtualItem objects, for restoring measurements through initialMeasurementsCache alongside the saved scrollOffset.

    3.15.0release notes

  • Adds the laneAssignmentMode option.

    3.14.0release notes

  • Adds instant to the ScrollBehavior type to match the W3C spec.

    3.13.22release notes

Performance 5

  • Multi-lane getMeasurements uses an incremental per-lane argmin for shortest-lane lookup, improving performance without changing placement output.

    3.17.4release notes

  • The default lanes === 1 path computes ranges without per-scroll-frame allocations, reducing GC pressure during continuous scrolling.

    3.17.3release notes

  • Redundant scroll events are skipped when the offset has not changed.

    3.17.2release notes

  • The default measureElement skips synchronous offsetWidth/offsetHeight reads when a cached size exists, reducing layout reflow on re-renders.

    3.17.0release notes

  • Skips synchronous DOM reads during normal scrolling.

    3.13.22release notes

Fixes and other changes 60

  • Computes offsets from current measurements rather than measurements from the last render; the first write of scrollToIndex also uses current measurements.

    3.19.11release notes

  • Fixes programmatic scrolling in horizontal RTL elements by converting logical offsets, including measurement adjustments, to negative DOM scroll offsets.

    3.19.11release notes

  • Keeps a full viewport of rows in the range when the scroll offset is past the end of the list, such as after the list shrinks and before the element reports its clamped position.

    3.19.10release notes

  • Avoids ResizeObserver loop errors by measuring new rows immediately, deferring their observation until the next frame, and stopping observation of detached rows before delivery ends.

    3.19.9release notes

  • A command issued during a touch fling now stops the fling on Android too.

    3.19.9release notes

  • Accounts for scrollMargin when deciding whether the viewport is at the end.

    3.19.8release notes

  • Holds a clamped compensation retry while a touch owns the scroll.

    3.19.7release notes

  • Cancels stale anchor work when an explicit scroll occurs.

    3.19.7release notes

  • Measures the scroll viewport using client dimensions so borders and scrollbars do not obscure end-aligned items.

    3.19.6release notes

  • Corrections made while disabled are no longer accumulated and carried over after re-enabling.

    3.19.5release notes

  • Commands now follow the scroll maximum through sizer changes and treat browser-clamped writes as their own, so commands can retarget and land instead of being cancelled or stopping short.

    3.19.5release notes

  • A target now moves with size corrections, prepends no longer overwrite commands with stale offsets, and an anchor is retained across a scroll event before adapter commit.

    3.19.5release notes

  • Corrections are deferred only for touch-driven scrolling on iOS, allowing programmatic landings to compensate before paint.

    3.19.5release notes

  • Corrections the element cannot currently apply are held, reflected in scrollOffset and the exposed rows and total size, then written when possible.

    3.19.5release notes

  • Changing the scroll element no longer carries over a pending iOS late-fling window that could defer corrections on the new element.

    3.19.5release notes

  • On iOS 27 and later, commands issued during a fling stop the fling and take effect at once; user takeover before the write still cancels the command.

    3.19.5release notes

  • When enabled, animation frames are requested from the scroll element's window and queued frames are canceled on cleanup, preventing lists in another window from stalling when the opener is minimized or occluded.

    3.19.4release notes

  • A second touchend or touchcancel inside the post-touch grace window restarts the window instead of allowing the first timer to end it early.

    3.19.3release notes

  • After the scroll element is swapped or the virtualizer disabled, writes to the old element are no longer matched to the new element's first scroll report.

    3.19.3release notes

  • Treats iOS touchcancel like touchend so interrupted gestures do not leave touch state stuck or keep scroll anchoring suppressed.

    3.19.2release notes

  • scrollBy is built on a just-written offset.

    3.19.1release notes

  • A user can end a non-smooth scrollToIndex before reconciliation sees it land; later measurement no longer pulls the user back to the old target.

    3.19.1release notes

  • Resizes measured before a scroll command's write is read back are preserved, preventing an upward scrollToIndex from jumping back and stalling.

    3.19.1release notes

  • A callback measures all entries before notifying, preventing a synchronous re-render from unmounting part of a row before it is measured.

    3.19.0release notes

  • iOS-deferred size corrections are no longer replayed after an in-flight scrollToIndex lands.

    3.19.0release notes

  • Doesn't cache a zero size when given a node that is not yet attached to the document.

    3.18.0release notes

  • For the last item with end alignment, avoids overshooting by paddingEnd and respects scrollPaddingEnd; use scrollToEnd() to include paddingEnd.

    3.18.0release notes

  • Keeps reconciliation active until pending ResizeObserver measurements can update the target, and respects external scrolling away from a reached target during settling.

    3.18.0release notes

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

    3.17.11release notes

  • Keeps a travelling smooth scroll alive when content is prepended, allowing the animation to continue to its recomputed target.

    3.17.11release notes

  • Keeps an end-pinned virtualizer following appended items when older items are trimmed in the same update without an increase in item count, while preserving reading anchors for users scrolled away from the end.

    3.17.10release notes

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

    3.17.10release notes

  • Retries a clamped end-anchored scroll compensation write after the sizer grows, recovering the bottom pin without yanking users when another scroll event occurs.

    3.17.9release notes

  • cleanup() now resets isScrolling and scrollDirection, preventing them from remaining stuck after the scroll element changes or is removed.

    3.17.8release notes

  • Connected measurement nodes with indexes outside the current item count are ignored.

    3.17.8release notes

  • When a resize compensation moves the scroll position, resizeItem now notifies synchronously so the transform commit lands in the same paint as the scroll write, preventing a one-frame viewport jump.

    3.17.7release notes

  • Re-measurements now compensate only items entirely above the fold, preventing viewport-spanning items that grow below the anchor point from moving the scroll position. First measurements and custom overrides are unchanged.

    3.17.6release notes

  • Absolute scroll commands invalidate pending deferred deltas because their targets use current measurements; relative scrollBy commands keep the deferral.

    3.17.5release notes

  • At the end clamp with anchorTo: 'end', stale negative compensation is dropped when the browser has already clamped to the correct bottom position; positive deltas still replay.

    3.17.5release notes

  • Clamp the tracked scrollOffset at 0 during end-anchor measurement compensation and re-anchoring in setOptions, preventing a phantom distance from end and wedged iOS deferred corrections.

    3.17.5release notes

  • cleanup() resets iOS gesture and deferral state so it does not leak across scroll element swaps.

    3.17.4release notes

  • A scroll event at the held offset after the virtualizer's own adjustment write no longer changes the direction, preserving above-viewport re-measure compensation.

    3.17.3release notes

  • The intended scroll adjustment is carried in scrollOffset so end-anchored streaming resize does not drift when the browser clamps the scrollTop write.

    3.17.2release notes

  • The default scroll-adjustment predicate now compensates scrollTop on the first measurement of an above-viewport item while scrolling backward, preventing items from jumping; it skips compensation only for re-measurements during backward scroll.

    3.17.1release notes

  • Eagerly adjusts scrollOffset during the render pass when items are prepended with anchorTo: 'end' and dynamic sizes, preventing a one-frame visible jump.

    3.16.1release notes

  • Cleanup of a disconnected node now finds its cache entry by node identity rather than calling getItemKey with a possibly stale index, preventing errors when items are removed while a ResizeObserver has the node queued.

    3.15.0release notes

  • The flush now rolls its accumulated delta into scrollAdjustments so a resize between the flush and resulting scroll event computes its next correction from the updated offset.

    3.15.0release notes

  • On iOS, scroll-position adjustments are deferred during touch, early momentum, and elastic overscroll; subpixel reconciliation and an overscroll clamp help prevent interrupted scrolling and snap-back jolts.

    3.15.0release notes

  • measure() resets pendingMin so a prior resizeItem() cannot preserve stale measurementsCache entries before that index; the next rebuild starts at 0.

    3.15.0release notes

  • Removes incorrect elementsCache cleanup using getItemKey.

    3.13.23release notes

  • Fixes smooth scrolling when item sizes are dynamic.

    3.13.21release notes

  • Returns early for disconnected nodes during element measurement.

    3.13.20release notes

  • Prevents a crash when a component unmounts during scrollToIndex by adding a null guard for targetWindow inside the requestAnimationFrame callback.

    3.13.19release notes

  • Preserves auto alignment for visible items when scrolling.

    3.13.17release notes

  • Aborts pending scroll operations when a new scrollToIndex is called.

    3.13.16release notes

  • Waits an extra frame for ResizeObserver measurements before verifying position, improving reliability in dynamic mode.

    3.13.16release notes

  • Scrolling to the last index now works properly.

    3.13.15release notes

  • Lane assignments are recalculated correctly when the lane count changes dynamically, preventing out-of-bounds errors and broken layouts.

    3.13.14release notes

  • When count changes, the virtualizer notifies the framework so getTotalSize() updates without manual useMemo workarounds.

    3.13.13release notes

  • Lane assignments are cached to prevent items from jumping between lanes when the viewport is resized.

    3.13.13release notes