NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #2183 most downloaded on npm
Headless UI for virtualizing scrollable elements in React
Last release 20 days ago
14 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 59 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
138 releases · first in 2022
One column per quarter.
Updated dependencies [ 06d1b6b , 2c0a0ea ]:
#1282 b48e3b0 - Skip flushSync for the synchronous notify raised from measureElement. React calls measureElement from a ref callback, i.e. while it is committing, and flushSync cannot flush there — it warns in development instead. The commit phase already runs at discrete (sync) priority, so the update lands in the same lane and the same frame without flushSync. Notifies from every other path (ResizeObserver re-measures, scroll adjustments) still flush synchronously.
Updated dependencies [06d1b6b, 2c0a0ea]:
Updated dependencies [ ab3278c ]:
ab3278c]:
Updated dependencies [ 4a0adf3 ]:
4a0adf3]:
Updated dependencies [ a0a411e , d2cf98b ]:
Updated dependencies \[`a5417b4`]:
a5417b4]:
Updated dependencies \[`7ae32b5`]:
#1237 aa536e7 - Fix a gap at the top of the list after an end-anchored prepend in directDomUpdates mode. The prepend grows the total size and bumps scrollOffset to the new bottom in the same pass, but the size container's height was written after _willUpdate synced the scroll position — so the browser clamped the scrollTop write to the stale (shorter) scrollHeight, leaving whitespace at the top until the next scroll. The container is now grown before the scroll sync. Only affected directDomUpdates mode (React-rendered sizers receive their height during render).
Updated dependencies [7ae32b5]:
Updated dependencies \[`1e3b908`, `7dcfc07`]:
Updated dependencies \[`6cbecd8`, `d49cc52`, `cf7834d`]:
Updated dependencies \[`767ead4`, `bc8643b`]:
Updated dependencies \[`b04f9ee`, `37be284`]:
Updated dependencies \[`7ae32b5`]:
7ae32b5]:
#1201 2ba5eb6 - Make directDomUpdates a no-op for direct DOM writes when containerRef is omitted. Previously the virtualizer still wrote item positions while never sizing the container (a broken half-state). Now omitting containerRef skips all direct writes while still skipping re-renders, letting consumers own the DOM updates themselves (e.g. in onChange).
Updated dependencies [ef69ea3]:
Updated dependencies \[`1e3b908`, `7dcfc07`]:
Updated dependencies \[`6cbecd8`, `d49cc52`, `cf7834d`]:
c746841]:
ab3278c]:
### Minor Changes - #1156 `2b39aef` - Add @tanstack/marko-virtual — a headless virtualisation adapter for Marko 6 using the runtime-tags API. Provides
directDomUpdates, directDomUpdatesMode, and containerRef. (#1180)bb4e0f1 - Re-export @tanstack/virtual-core from @tanstack/lit-virtual, so the core API (Virtualizer, defaultRangeExtractor, measureElement, the scroll observers and the shared types) can be imported from the adapter without adding @tanstack/virtual-core as a second dependency. Every other framework adapter already does this.4a0adf3]:
Updated dependencies \[`fc992ab`]:
fc992ab]:
Updated dependencies \[`99355ad`, `99355ad`, `99355ad`, `99355ad`, `99355ad`, `99355ad`, `99355ad`]:
useReducer(() => ({}), {}) force-rerender pattern with an (#1168)
incrementing number counter. Same semantics (every dispatch changes the
reducer state, forcing a render); zero per-dispatch object allocation.
Trivial individual cost, but eliminates one steady-state GC source on
scroll-heavy apps.99355ad, 99355ad, 99355ad, 99355ad, 99355ad, 99355ad, 99355ad]:
97a204d]:
Updated dependencies \[`97a204d`]:
97a204d]:
7ece2d5]:
Updated dependencies \[`7ece2d5`]:
7ece2d5]:
Updated dependencies \[`54d771a`, `d3416c3`]:
be89e29]:
Updated dependencies \[`be89e29`]:
be89e29]:
ff83e94]:
Updated dependencies \[`843109c`]:
843109c]:
ff83e94]:
Updated dependencies \[`843109c`]:
843109c]:
scrollToIndex by adding a null guard for targetWindow inside the requestAnimationFrame callback (#1129)9067574]:
Updated dependencies \[`9067574`]:
9067574]:
21d9a46]:
Updated dependencies \[`21d9a46`]:
21d9a46]:
db6df21]:
Updated dependencies \[`db6df21`]:
db6df21]:
5a273bf]:
Updated dependencies \[`5a273bf`]:
5a273bf]:
feat(react-virtual): add useFlushSync option (#1100)
Adds a React-specific useFlushSync option to control whether flushSync is used for synchronous scroll correction during measurement.
The default behavior remains unchanged (useFlushSync: true) to preserve the best scrolling experience.
Disabling it avoids the React 19 warning about calling flushSync during render, at the cost of potentially increased visible whitespace during fast scrolling with dynamically sized items.
Updated dependencies [5a273bf]:
6d9274c]:
Updated dependencies \[`6d9274c`]:
6d9274c]:
Fix: Correct lane assignments when lane count changes dynamically (#1095)
Fixed a critical bug where changing the number of lanes dynamically would cause layout breakage with incorrect lane assignments. When the lane count changed (e.g., from 3 to 2 columns in a responsive masonry layout), some virtual items would retain their old lane numbers, causing out-of-bounds errors and broken layouts.
Root Cause: After clearing measurements cache on lane change, the virtualizer was incorrectly restoring data from initialMeasurementsCache, which contained stale lane assignments from the previous lane count.
Fix: Skip initialMeasurementsCache restoration during lane transitions by checking the lanesSettling flag. This ensures all measurements are recalculated with correct lane assignments for the new lane count.
Before:
// With lanes = 2
virtualItems.forEach((item) => {
columns[item.lane].push(item) // ❌ Error: item.lane could be 3
})
After:
// With lanes = 2
virtualItems.forEach((item) => {
columns[item.lane].push(item) // ✅ item.lane is always 0 or 1
})
This fix is essential for responsive masonry layouts where column count changes based on viewport width. No performance impact as it only affects the lane change transition path.
Fix: Notify framework when count changes to update getTotalSize() (#1085)
Fixed an issue where getTotalSize() would return stale values when the count option changed (e.g., during filtering or search operations). The virtualizer now automatically notifies the framework when measurement-affecting options change, ensuring the UI updates correctly without requiring manual useMemo workarounds.
Before: When filtering items, the list container would maintain its previous height, causing excessive blank space (when count decreased) or inaccessible items (when count increased).
After: Height updates automatically when count changes, providing the correct user experience.
This fix applies to all framework adapters and has minimal performance impact (< 0.1ms per change).
Updated dependencies [2542c5a, 96e32a6]:
Fix: Notify framework when count changes to update getTotalSize()
Fix: Notify framework when count changes to update getTotalSize() (#1085)
Fixed an issue where getTotalSize() would return stale values when the count option changed (e.g., during filtering or search operations). The virtualizer now automatically notifies the framework when measurement-affecting options change, ensuring the UI updates correctly without requiring manual useMemo workarounds.
Before: When filtering items, the list container would maintain its previous height, causing excessive blank space (when count decreased) or inaccessible items (when count increased).
After: Height updates automatically when count changes, providing the correct user experience.
This fix applies to all framework adapters and has minimal performance impact (< 0.1ms per change).
Updated dependencies [2542c5a, 96e32a6]:
Fix: Notify framework when count changes to update getTotalSize() (#1085)
Fixed an issue where getTotalSize() would return stale values when the count option changed (e.g., during filtering or search operations). The virtualizer now automatically notifies the framework when measurement-affecting options change, ensuring the UI updates correctly without requiring manual useMemo workarounds.
Before: When filtering items, the list container would maintain its previous height, causing excessive blank space (when count decreased) or inaccessible items (when count increased).
After: Height updates automatically when count changes, providing the correct user experience.
This fix applies to all framework adapters and has minimal performance impact (< 0.1ms per change).
fix: stabilize lane assignments in masonry layout (#1080)
Added lane assignment caching to prevent items from jumping between lanes when viewport is resized. Previously, items could shift to different lanes during resize due to recalculating "shortest lane" with slightly different heights.
Changes:
laneAssignments cache (Map<index, lane>) to persist lane assignmentslanes option changes or measure() is calledcount decreases (removes stale entries)fix(lit-virtual): create Virtualizer instance before hostConnected (#1061)
When creating an instance of the reactive controller in connectedCallback, calling addController will synchronously call hostConnected on the controller. This means that this.virtualizer will still be undefined.
Updated dependencies \[`d21ed98`]:
d21ed98]:
Updated dependencies \[`73fa867`]:
73fa867]:
Updated dependencies \[`b3b7e7d`]:
b3b7e7d]:
Updated dependencies \[`9e33cdb`]:
9e33cdb]:
Error: Unexpected undefined (#1004)Updated dependencies \[`60719f6`]:
60719f6]:
Updated dependencies \[`e2d93c2`]:
e2d93c2]:
Updated dependencies \[`042616f`]:
042616f]:
042616f)Updated dependencies \[`51656d9`]:
51656d9]:
Updated dependencies \[`514b62d`, `f03d814`]:
Updated dependencies \[`02ef309`]:
02ef309]:
Version 3.13.2 - 2/25/25, 7:40 AM
Version 3.13.2 - 2/25/25, 7:40 AM
Version 3.13.1 - 2/25/25, 6:21 AM
Version 3.13.1 - 2/25/25, 6:21 AM
Version 3.13.0 - 2/7/25, 12:12 PM
Version 3.13.0 - 2/7/25, 12:12 PM
Version 3.12.1 - 2/7/25, 5:12 AM
Version 3.12.1 - 2/7/25, 5:12 AM
Version 3.12.0 - 2/3/25, 4:02 AM
Version 3.12.0 - 2/3/25, 4:02 AM
Version 3.11.3 - 1/27/25, 10:57 AM
Version 3.11.3 - 1/27/25, 10:57 AM
Version 3.11.2 - 12/16/24, 2:10 PM
Version 3.11.2 - 12/16/24, 2:10 PM
Version 3.11.1 - 12/9/24, 6:48 PM
Version 3.11.1 - 12/9/24, 6:48 PM
Version 3.11.0 - 12/6/24, 11:45 AM
Version 3.11.0 - 12/6/24, 11:45 AM
Version 3.10.9 - 11/7/24, 11:07 AM
Version 3.10.9 - 11/7/24, 11:07 AM
useScrollendEvent option (#875) (375cd83) by @hshojaVersion 3.10.8 - 9/16/24, 2:22 PM
Version 3.10.8 - 9/16/24, 2:22 PM
Version 3.10.7 - 9/4/24, 1:15 PM
Version 3.10.7 - 9/4/24, 1:15 PM
Version 3.10.6 - 8/29/24, 9:29 AM
Version 3.10.6 - 8/29/24, 9:29 AM
Version 3.10.5 - 8/27/24, 1:39 PM
Version 3.10.5 - 8/27/24, 1:39 PM
Version 3.10.4 - 8/23/24, 12:29 PM
Version 3.10.4 - 8/23/24, 12:29 PM
examples: replace deprecated faker.datatype.number (#805) (eebc3e7) by @piecyk
Version 3.10.2 - 8/22/24, 1:00 PM
Version 3.10.1 - 8/20/24, 3:57 AM
Version 3.10.1 - 8/20/24, 3:57 AM
Nothing published for this version
Version 3.9.0 - 8/14/24, 12:20 PM
Version 3.9.0 - 8/14/24, 12:20 PM
Version 3.8.6 - 8/9/24, 5:43 AM
Version 3.8.6 - 8/9/24, 5:43 AM
Version 3.8.4 - 7/30/24, 6:57 AM
Version 3.8.4 - 7/30/24, 6:57 AM
Version 3.8.3 - 7/11/24, 4:12 AM (Manual Release)
Version 3.8.3 - 7/11/24, 4:12 AM (Manual Release)
Your coding agent can read these notes before it upgrades. Set up the MCP server →