diff --git a/benchmarks/CHANGELOG.md b/benchmarks/CHANGELOG.md
index 2c773352..74c55e3d 100644
--- a/benchmarks/CHANGELOG.md
+++ b/benchmarks/CHANGELOG.md
@@ -1,5 +1,19 @@
# @tanstack/virtual-benchmarks
+## 0.0.4
+
+### Patch Changes
+
+- Updated dependencies []:
+ - @tanstack/react-virtual@3.14.1
+
+## 0.0.3
+
+### Patch Changes
+
+- Updated dependencies [[`73e115d`](https://github.com/TanStack/virtual/commit/73e115d53faf01f073bc4a7bd71ee0139307f4a8)]:
+ - @tanstack/react-virtual@3.14.0
+
## 0.0.2
### Patch Changes
diff --git a/benchmarks/package.json b/benchmarks/package.json
index c900a764..1895185b 100644
--- a/benchmarks/package.json
+++ b/benchmarks/package.json
@@ -1,7 +1,7 @@
{
"name": "@tanstack/virtual-benchmarks",
"private": true,
- "version": "0.0.2",
+ "version": "0.0.4",
"type": "module",
"scripts": {
"dev": "vite",
diff --git a/examples/angular/dynamic/package.json b/examples/angular/dynamic/package.json
index 41e86f09..caf7ec62 100644
--- a/examples/angular/dynamic/package.json
+++ b/examples/angular/dynamic/package.json
@@ -18,7 +18,7 @@
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
"@faker-js/faker": "^8.4.1",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/fixed/package.json b/examples/angular/fixed/package.json
index fc87e7b9..5791444f 100644
--- a/examples/angular/fixed/package.json
+++ b/examples/angular/fixed/package.json
@@ -17,7 +17,7 @@
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/infinite-scroll/package.json b/examples/angular/infinite-scroll/package.json
index ee094cae..35f1adcf 100644
--- a/examples/angular/infinite-scroll/package.json
+++ b/examples/angular/infinite-scroll/package.json
@@ -18,7 +18,7 @@
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
"@tanstack/angular-query-experimental": "5.80.7",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/padding/package.json b/examples/angular/padding/package.json
index 53839b2f..189dde6f 100644
--- a/examples/angular/padding/package.json
+++ b/examples/angular/padding/package.json
@@ -17,7 +17,7 @@
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/smooth-scroll/package.json b/examples/angular/smooth-scroll/package.json
index 1539938d..b82d0077 100644
--- a/examples/angular/smooth-scroll/package.json
+++ b/examples/angular/smooth-scroll/package.json
@@ -17,7 +17,7 @@
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/sticky/package.json b/examples/angular/sticky/package.json
index 0bea4142..0683db65 100644
--- a/examples/angular/sticky/package.json
+++ b/examples/angular/sticky/package.json
@@ -18,7 +18,7 @@
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
"@faker-js/faker": "^8.4.1",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/table/package.json b/examples/angular/table/package.json
index 89956c47..d035bcf1 100644
--- a/examples/angular/table/package.json
+++ b/examples/angular/table/package.json
@@ -19,7 +19,7 @@
"@angular/router": "^19.0.0",
"@faker-js/faker": "^8.4.1",
"@tanstack/angular-table": "8.21.3",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/variable/package.json b/examples/angular/variable/package.json
index cadb1fdd..2959961d 100644
--- a/examples/angular/variable/package.json
+++ b/examples/angular/variable/package.json
@@ -17,7 +17,7 @@
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/angular/window/package.json b/examples/angular/window/package.json
index de71f556..8d3b461d 100644
--- a/examples/angular/window/package.json
+++ b/examples/angular/window/package.json
@@ -17,7 +17,7 @@
"@angular/platform-browser": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0",
"@angular/router": "^19.0.0",
- "@tanstack/angular-virtual": "^5.0.2",
+ "@tanstack/angular-virtual": "^5.0.3",
"rxjs": "^7.8.2",
"tslib": "^2.8.1",
"zone.js": "0.15.1"
diff --git a/examples/lit/dynamic/package.json b/examples/lit/dynamic/package.json
index a9621671..1607f9f5 100644
--- a/examples/lit/dynamic/package.json
+++ b/examples/lit/dynamic/package.json
@@ -9,8 +9,8 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/lit-virtual": "^3.13.27",
- "@tanstack/virtual-core": "^3.16.0",
+ "@tanstack/lit-virtual": "^3.13.28",
+ "@tanstack/virtual-core": "^3.16.1",
"lit": "^3.3.0"
},
"devDependencies": {
diff --git a/examples/lit/fixed/package.json b/examples/lit/fixed/package.json
index 40f02887..9b811565 100644
--- a/examples/lit/fixed/package.json
+++ b/examples/lit/fixed/package.json
@@ -9,8 +9,8 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/lit-virtual": "^3.13.27",
- "@tanstack/virtual-core": "^3.16.0",
+ "@tanstack/lit-virtual": "^3.13.28",
+ "@tanstack/virtual-core": "^3.16.1",
"lit": "^3.3.0"
},
"devDependencies": {
diff --git a/examples/react/chat/package.json b/examples/react/chat/package.json
index b265f878..038026fe 100644
--- a/examples/react/chat/package.json
+++ b/examples/react/chat/package.json
@@ -8,7 +8,7 @@
"serve": "vite preview"
},
"dependencies": {
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/chat/src/main.tsx b/examples/react/chat/src/main.tsx
index 2f4d9a17..7329f8f2 100644
--- a/examples/react/chat/src/main.tsx
+++ b/examples/react/chat/src/main.tsx
@@ -43,11 +43,15 @@ function App() {
count: messages.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 74,
- getItemKey: (index) => messages[index]!.id,
+ getItemKey: React.useCallback(
+ (index: number) => messages[index]!.id,
+ [messages],
+ ),
anchorTo: 'end',
followOnAppend: true,
scrollEndThreshold: 80,
overscan: 6,
+ directDomUpdates: true,
})
const virtualItems = virtualizer.getVirtualItems()
@@ -180,8 +184,8 @@ function App() {
}}
>
diff --git a/examples/react/dynamic/package.json b/examples/react/dynamic/package.json
index 395d4b11..777846ab 100644
--- a/examples/react/dynamic/package.json
+++ b/examples/react/dynamic/package.json
@@ -9,7 +9,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/dynamic/src/main.tsx b/examples/react/dynamic/src/main.tsx
index 1a0fe0ae..5e4b2b7e 100644
--- a/examples/react/dynamic/src/main.tsx
+++ b/examples/react/dynamic/src/main.tsx
@@ -24,14 +24,13 @@ function RowVirtualizerDynamic() {
getScrollElement: () => parentRef.current,
estimateSize: () => 45,
enabled,
+ directDomUpdates: true,
})
React.useEffect(() => {
virtualizer.scrollToIndex(count - 1, { align: 'end' })
}, [])
- const items = virtualizer.getVirtualItems()
-
return (
diff --git a/examples/react/fixed/package.json b/examples/react/fixed/package.json
index 599d9409..5df29ada 100644
--- a/examples/react/fixed/package.json
+++ b/examples/react/fixed/package.json
@@ -8,7 +8,7 @@
"serve": "vite preview"
},
"dependencies": {
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/infinite-scroll/package.json b/examples/react/infinite-scroll/package.json
index c1c4bfd8..2fa5c762 100644
--- a/examples/react/infinite-scroll/package.json
+++ b/examples/react/infinite-scroll/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@tanstack/react-query": "^5.80.7",
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/padding/package.json b/examples/react/padding/package.json
index 2fd58799..e2afa43e 100644
--- a/examples/react/padding/package.json
+++ b/examples/react/padding/package.json
@@ -9,7 +9,7 @@
"start": "vite"
},
"dependencies": {
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/pretext/package.json b/examples/react/pretext/package.json
index 9e1dd5f5..e05b1db2 100644
--- a/examples/react/pretext/package.json
+++ b/examples/react/pretext/package.json
@@ -9,7 +9,7 @@
},
"dependencies": {
"@chenglou/pretext": "^0.0.7",
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/scroll-padding/package.json b/examples/react/scroll-padding/package.json
index e09bf120..809ef56d 100644
--- a/examples/react/scroll-padding/package.json
+++ b/examples/react/scroll-padding/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@react-hookz/web": "^25.1.1",
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/smooth-scroll/package.json b/examples/react/smooth-scroll/package.json
index acf85b83..37ade224 100644
--- a/examples/react/smooth-scroll/package.json
+++ b/examples/react/smooth-scroll/package.json
@@ -9,7 +9,7 @@
"start": "vite"
},
"dependencies": {
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/sticky/package.json b/examples/react/sticky/package.json
index ab1e4734..1581be9f 100644
--- a/examples/react/sticky/package.json
+++ b/examples/react/sticky/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"lodash": "^4.17.21",
"react": "^18.3.1",
"react-dom": "^18.3.1"
diff --git a/examples/react/table/package.json b/examples/react/table/package.json
index 72e8dce5..d1f647a8 100644
--- a/examples/react/table/package.json
+++ b/examples/react/table/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@faker-js/faker": "^8.4.1",
"@tanstack/react-table": "^8.21.3",
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/variable/package.json b/examples/react/variable/package.json
index d7027222..361bc8a6 100644
--- a/examples/react/variable/package.json
+++ b/examples/react/variable/package.json
@@ -9,7 +9,7 @@
"start": "vite"
},
"dependencies": {
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/react/window/package.json b/examples/react/window/package.json
index 27a602e5..7d36a7ff 100644
--- a/examples/react/window/package.json
+++ b/examples/react/window/package.json
@@ -8,7 +8,7 @@
"serve": "vite preview"
},
"dependencies": {
- "@tanstack/react-virtual": "^3.13.26",
+ "@tanstack/react-virtual": "^3.14.1",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
diff --git a/examples/svelte/dynamic/package.json b/examples/svelte/dynamic/package.json
index a5a10cd2..ee8d4735 100644
--- a/examples/svelte/dynamic/package.json
+++ b/examples/svelte/dynamic/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/svelte-virtual": "^3.13.26"
+ "@tanstack/svelte-virtual": "^3.13.27"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.2",
diff --git a/examples/svelte/fixed/package.json b/examples/svelte/fixed/package.json
index 27fe362d..71494152 100644
--- a/examples/svelte/fixed/package.json
+++ b/examples/svelte/fixed/package.json
@@ -9,7 +9,7 @@
"check": "svelte-check --tsconfig ./tsconfig.json"
},
"dependencies": {
- "@tanstack/svelte-virtual": "^3.13.26"
+ "@tanstack/svelte-virtual": "^3.13.27"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.2",
diff --git a/examples/svelte/infinite-scroll/package.json b/examples/svelte/infinite-scroll/package.json
index ecf02098..dd3bb309 100644
--- a/examples/svelte/infinite-scroll/package.json
+++ b/examples/svelte/infinite-scroll/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@tanstack/svelte-query": "^5.80.7",
- "@tanstack/svelte-virtual": "^3.13.26"
+ "@tanstack/svelte-virtual": "^3.13.27"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.2",
diff --git a/examples/svelte/smooth-scroll/package.json b/examples/svelte/smooth-scroll/package.json
index 64487f0a..8771bf56 100644
--- a/examples/svelte/smooth-scroll/package.json
+++ b/examples/svelte/smooth-scroll/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/svelte-virtual": "^3.13.26"
+ "@tanstack/svelte-virtual": "^3.13.27"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.2",
diff --git a/examples/svelte/sticky/package.json b/examples/svelte/sticky/package.json
index 31e1682c..8f3c878c 100644
--- a/examples/svelte/sticky/package.json
+++ b/examples/svelte/sticky/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/svelte-virtual": "^3.13.26",
+ "@tanstack/svelte-virtual": "^3.13.27",
"lodash": "^4.17.21"
},
"devDependencies": {
diff --git a/examples/svelte/table/package.json b/examples/svelte/table/package.json
index b84efcf1..063acfec 100644
--- a/examples/svelte/table/package.json
+++ b/examples/svelte/table/package.json
@@ -11,7 +11,7 @@
"dependencies": {
"@faker-js/faker": "^8.4.1",
"@tanstack/svelte-table": "^8.21.3",
- "@tanstack/svelte-virtual": "^3.13.26"
+ "@tanstack/svelte-virtual": "^3.13.27"
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.2",
diff --git a/examples/vue/dynamic/package.json b/examples/vue/dynamic/package.json
index bc9cf174..71c1282c 100644
--- a/examples/vue/dynamic/package.json
+++ b/examples/vue/dynamic/package.json
@@ -9,7 +9,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/examples/vue/fixed/package.json b/examples/vue/fixed/package.json
index e15cafd2..781e646a 100644
--- a/examples/vue/fixed/package.json
+++ b/examples/vue/fixed/package.json
@@ -8,7 +8,7 @@
"preview": "vite preview"
},
"dependencies": {
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/examples/vue/infinite-scroll/package.json b/examples/vue/infinite-scroll/package.json
index 7bdf6347..a7d6addc 100644
--- a/examples/vue/infinite-scroll/package.json
+++ b/examples/vue/infinite-scroll/package.json
@@ -9,7 +9,7 @@
},
"dependencies": {
"@tanstack/vue-query": "^5.80.7",
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/examples/vue/padding/package.json b/examples/vue/padding/package.json
index 9fb10414..97a5c987 100644
--- a/examples/vue/padding/package.json
+++ b/examples/vue/padding/package.json
@@ -8,7 +8,7 @@
"preview": "vite preview"
},
"dependencies": {
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/examples/vue/scroll-padding/package.json b/examples/vue/scroll-padding/package.json
index 2389fb6c..375a97b0 100644
--- a/examples/vue/scroll-padding/package.json
+++ b/examples/vue/scroll-padding/package.json
@@ -8,7 +8,7 @@
"preview": "vite preview"
},
"dependencies": {
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"@vueuse/core": "^12.8.2",
"vue": "^3.5.16"
},
diff --git a/examples/vue/smooth-scroll/package.json b/examples/vue/smooth-scroll/package.json
index ff740cf5..f533d980 100644
--- a/examples/vue/smooth-scroll/package.json
+++ b/examples/vue/smooth-scroll/package.json
@@ -8,7 +8,7 @@
"preview": "vite preview"
},
"dependencies": {
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/examples/vue/sticky/package.json b/examples/vue/sticky/package.json
index 418a074c..ec478aba 100644
--- a/examples/vue/sticky/package.json
+++ b/examples/vue/sticky/package.json
@@ -9,7 +9,7 @@
},
"dependencies": {
"@faker-js/faker": "^8.4.1",
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"lodash": "^4.17.21",
"vue": "^3.5.16"
},
diff --git a/examples/vue/table/package.json b/examples/vue/table/package.json
index c6d541b1..a7734453 100644
--- a/examples/vue/table/package.json
+++ b/examples/vue/table/package.json
@@ -10,7 +10,7 @@
"dependencies": {
"@faker-js/faker": "^8.4.1",
"@tanstack/vue-table": "^8.21.3",
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/examples/vue/variable/package.json b/examples/vue/variable/package.json
index 384a4b49..13d81e6e 100644
--- a/examples/vue/variable/package.json
+++ b/examples/vue/variable/package.json
@@ -8,7 +8,7 @@
"preview": "vite preview"
},
"dependencies": {
- "@tanstack/vue-virtual": "^3.13.26",
+ "@tanstack/vue-virtual": "^3.13.27",
"vue": "^3.5.16"
},
"devDependencies": {
diff --git a/packages/angular-virtual/CHANGELOG.md b/packages/angular-virtual/CHANGELOG.md
index 4e96548e..e2f4f088 100644
--- a/packages/angular-virtual/CHANGELOG.md
+++ b/packages/angular-virtual/CHANGELOG.md
@@ -1,5 +1,12 @@
# @tanstack/angular-virtual
+## 5.0.3
+
+### Patch Changes
+
+- Updated dependencies [[`c746841`](https://github.com/TanStack/virtual/commit/c7468416354c203cd7cc952da5997073394224fb)]:
+ - @tanstack/virtual-core@3.16.1
+
## 5.0.2
### Patch Changes
diff --git a/packages/angular-virtual/package.json b/packages/angular-virtual/package.json
index eac8041a..b6449b4e 100644
--- a/packages/angular-virtual/package.json
+++ b/packages/angular-virtual/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/angular-virtual",
- "version": "5.0.2",
+ "version": "5.0.3",
"description": "Headless UI for virtualizing scrollable elements in Angular",
"author": "Garrett Darnell",
"license": "MIT",
diff --git a/packages/lit-virtual/CHANGELOG.md b/packages/lit-virtual/CHANGELOG.md
index af1dd376..0ad1acce 100644
--- a/packages/lit-virtual/CHANGELOG.md
+++ b/packages/lit-virtual/CHANGELOG.md
@@ -1,5 +1,12 @@
# @tanstack/lit-virtual
+## 3.13.28
+
+### Patch Changes
+
+- Updated dependencies [[`c746841`](https://github.com/TanStack/virtual/commit/c7468416354c203cd7cc952da5997073394224fb)]:
+ - @tanstack/virtual-core@3.16.1
+
## 3.13.27
### Patch Changes
diff --git a/packages/lit-virtual/package.json b/packages/lit-virtual/package.json
index 9ef1d117..f5f399f3 100644
--- a/packages/lit-virtual/package.json
+++ b/packages/lit-virtual/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/lit-virtual",
- "version": "3.13.27",
+ "version": "3.13.28",
"description": "Headless UI for virtualizing scrollable elements in Lit",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/react-virtual/CHANGELOG.md b/packages/react-virtual/CHANGELOG.md
index 6371e7b6..c557b022 100644
--- a/packages/react-virtual/CHANGELOG.md
+++ b/packages/react-virtual/CHANGELOG.md
@@ -1,5 +1,18 @@
# @tanstack/react-virtual
+## 3.14.1
+
+### Patch Changes
+
+- Updated dependencies [[`c746841`](https://github.com/TanStack/virtual/commit/c7468416354c203cd7cc952da5997073394224fb)]:
+ - @tanstack/virtual-core@3.16.1
+
+## 3.14.0
+
+### Minor Changes
+
+- Add opt-in direct DOM updates for scroll positioning with `directDomUpdates`, `directDomUpdatesMode`, and `containerRef`. ([#1180](https://github.com/TanStack/virtual/pull/1180))
+
## 3.13.26
### Patch Changes
diff --git a/packages/react-virtual/e2e/app/direct-dom-updates/index.html b/packages/react-virtual/e2e/app/direct-dom-updates/index.html
new file mode 100644
index 00000000..56f418f6
--- /dev/null
+++ b/packages/react-virtual/e2e/app/direct-dom-updates/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/react-virtual/e2e/app/direct-dom-updates/main.tsx b/packages/react-virtual/e2e/app/direct-dom-updates/main.tsx
new file mode 100644
index 00000000..e40673d1
--- /dev/null
+++ b/packages/react-virtual/e2e/app/direct-dom-updates/main.tsx
@@ -0,0 +1,70 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import { useVirtualizer } from '@tanstack/react-virtual'
+
+const ITEM_SIZE = 40
+const COUNT = 1000
+
+const App = () => {
+ const parentRef = React.useRef
(null)
+
+ const params = new URLSearchParams(window.location.search)
+ const mode = (params.get('mode') ?? 'transform') as 'position' | 'transform'
+
+ const renderCount = React.useRef(0)
+ renderCount.current += 1
+
+ const rowVirtualizer = useVirtualizer({
+ count: COUNT,
+ getScrollElement: () => parentRef.current,
+ estimateSize: () => ITEM_SIZE,
+ overscan: 2,
+ directDomUpdates: true,
+ directDomUpdatesMode: mode,
+ })
+
+ return (
+
+
{renderCount.current}
+
{mode}
+
+
+
+
+ )
+}
+
+ReactDOM.createRoot(document.getElementById('root')!).render()
diff --git a/packages/react-virtual/e2e/app/test/direct-dom-updates.spec.ts b/packages/react-virtual/e2e/app/test/direct-dom-updates.spec.ts
new file mode 100644
index 00000000..c20c7050
--- /dev/null
+++ b/packages/react-virtual/e2e/app/test/direct-dom-updates.spec.ts
@@ -0,0 +1,93 @@
+import { expect, test } from '@playwright/test'
+
+const ITEM_SIZE = 40
+const COUNT = 1000
+
+for (const mode of ['position', 'transform'] as const) {
+ test.describe(`directDomUpdates mode=${mode}`, () => {
+ test('sets container size and positions items via direct DOM updates', async ({
+ page,
+ }) => {
+ await page.goto(`/direct-dom-updates/?mode=${mode}`)
+
+ await expect(page.locator('[data-testid="mode"]')).toHaveText(mode)
+
+ // Container height is written directly by containerRef, NOT from JSX style.
+ const inner = page.locator('#inner')
+ await expect(inner).toHaveAttribute(
+ 'style',
+ new RegExp(`height:\\s*${COUNT * ITEM_SIZE}px`),
+ )
+
+ // First item is at top 0 (position) or translate3d(0, 0, 0) (transform).
+ const first = page.locator('[data-testid="item-0"]')
+ await expect(first).toBeVisible()
+ if (mode === 'position') {
+ await expect(first).toHaveAttribute('style', /top:\s*0px/)
+ } else {
+ await expect(first).toHaveAttribute(
+ 'style',
+ /translate3d\(0px,\s*0px,\s*0px\)/,
+ )
+ }
+ })
+
+ test('scrolling moves items via direct DOM without per-pixel React re-renders', async ({
+ page,
+ }) => {
+ await page.goto(`/direct-dom-updates/?mode=${mode}`)
+
+ const initialRenders = Number(
+ await page.locator('[data-testid="render-count"]').textContent(),
+ )
+
+ // Scroll by exactly one item — does NOT change the visible range
+ // (overscan absorbs it), so React should not re-render.
+ await page.locator('#scroll-container').evaluate((el, by) => {
+ el.scrollTop = by
+ }, ITEM_SIZE)
+
+ const item1 = page.locator('[data-testid="item-1"]')
+ await expect(item1).toHaveAttribute(
+ 'style',
+ mode === 'position'
+ ? /top:\s*40px/
+ : /translate3d\(0px,\s*40px,\s*0px\)/,
+ )
+
+ const renderAfterSmallScroll = Number(
+ await page.locator('[data-testid="render-count"]').textContent(),
+ )
+ // Allow at most 1 extra render (isScrolling flip), zero for the offset itself.
+ expect(renderAfterSmallScroll - initialRenders).toBeLessThanOrEqual(2)
+ })
+
+ test('large scroll triggers a re-render and items still position correctly', async ({
+ page,
+ }) => {
+ await page.goto(`/direct-dom-updates/?mode=${mode}`)
+
+ const before = Number(
+ await page.locator('[data-testid="render-count"]').textContent(),
+ )
+
+ await page.click('#scroll-to-500')
+
+ // Wait for the new range to render.
+ await expect(page.locator('[data-testid="item-500"]')).toBeVisible()
+
+ const after = Number(
+ await page.locator('[data-testid="render-count"]').textContent(),
+ )
+ expect(after).toBeGreaterThan(before)
+
+ const item500 = page.locator('[data-testid="item-500"]')
+ const style = (await item500.getAttribute('style')) ?? ''
+ if (mode === 'position') {
+ expect(style).toMatch(/top:\s*20000px/)
+ } else {
+ expect(style).toMatch(/translate3d\(0px,\s*20000px,\s*0px\)/)
+ }
+ })
+ })
+}
diff --git a/packages/react-virtual/e2e/app/vite.config.ts b/packages/react-virtual/e2e/app/vite.config.ts
index 964267f3..70a1602f 100644
--- a/packages/react-virtual/e2e/app/vite.config.ts
+++ b/packages/react-virtual/e2e/app/vite.config.ts
@@ -16,6 +16,10 @@ export default defineConfig({
),
'smooth-scroll': path.resolve(__dirname, 'smooth-scroll/index.html'),
'stale-index': path.resolve(__dirname, 'stale-index/index.html'),
+ 'direct-dom-updates': path.resolve(
+ __dirname,
+ 'direct-dom-updates/index.html',
+ ),
},
},
},
diff --git a/packages/react-virtual/package.json b/packages/react-virtual/package.json
index 21411bbb..e358a2e8 100644
--- a/packages/react-virtual/package.json
+++ b/packages/react-virtual/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/react-virtual",
- "version": "3.13.26",
+ "version": "3.14.1",
"description": "Headless UI for virtualizing scrollable elements in React",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/react-virtual/src/index.tsx b/packages/react-virtual/src/index.tsx
index 89678ad6..ab39cb15 100644
--- a/packages/react-virtual/src/index.tsx
+++ b/packages/react-virtual/src/index.tsx
@@ -16,11 +16,57 @@ export * from '@tanstack/virtual-core'
const useIsomorphicLayoutEffect =
typeof document !== 'undefined' ? React.useLayoutEffect : React.useEffect
+export type ReactVirtualizer<
+ TScrollElement extends Element | Window,
+ TItemElement extends Element,
+> = Virtualizer & {
+ /**
+ * Ref callback for the inner sized container element. Only meaningful when
+ * `directDomUpdates: true` — the virtualizer writes the container's
+ * main-axis size (`height` or `width`) directly to skip React re-renders.
+ */
+ containerRef: (node: HTMLElement | null) => void
+}
+
export type ReactVirtualizerOptions<
TScrollElement extends Element | Window,
TItemElement extends Element,
> = VirtualizerOptions & {
useFlushSync?: boolean
+ /**
+ * Skip React re-renders for scroll-only updates. The virtualizer writes
+ * item positions (`top`/`left`) and the container size (`height`/`width`)
+ * directly to the DOM, and only re-renders when the visible index range
+ * or `isScrolling` changes.
+ *
+ * Requirements when enabled:
+ * - Item elements must be `position: absolute`; in `'transform'` mode they
+ * must also be anchored with `top: 0` / `left: 0`.
+ * - Item elements must NOT set the main-axis position in their style — the
+ * virtualizer owns `top` / `left` in `'position'` mode and `transform` in
+ * `'transform'` mode.
+ * - The inner sized container must receive `virtualizer.containerRef` and
+ * must NOT set `height` / `width` in its style.
+ * - For multi-lane layouts (grids / masonry), the cross-axis position
+ * (e.g. `left: ${(item.lane * 100) / lanes}%`) is stable per item and
+ * must still be set in your JSX — only the main axis is automated.
+ *
+ * This flag is intended to be set once at mount. Toggling it (or
+ * `directDomUpdatesMode`) at runtime can leave stale inline styles on
+ * items and the container.
+ */
+ directDomUpdates?: boolean
+ /**
+ * How `directDomUpdates` positions item elements.
+ * - `'transform'` (default): writes `transform: translate3d(...)`.
+ * Promotes items to their own compositor layer — usually smoother on long
+ * lists, but creates a stacking context and can interfere with
+ * `position: fixed` descendants. Item elements must still be anchored with
+ * `position: absolute`, `top: 0`, and `left: 0`.
+ * - `'position'`: writes `top` / `left`. Item elements must be
+ * `position: absolute`.
+ */
+ directDomUpdatesMode?: 'position' | 'transform'
}
function useVirtualizerBase<
@@ -28,28 +74,129 @@ function useVirtualizerBase<
TItemElement extends Element,
>({
useFlushSync = true,
+ directDomUpdates = false,
+ directDomUpdatesMode = 'transform',
...options
-}: ReactVirtualizerOptions): Virtualizer<
+}: ReactVirtualizerOptions): ReactVirtualizer<
TScrollElement,
TItemElement
> {
const rerender = React.useReducer((x: number) => x + 1, 0)[1]
+ // Mutable across renders so the onChange closure captured by setOptions
+ // always reads the latest values without us having to re-create it.
+ const directRef = React.useRef({
+ enabled: directDomUpdates,
+ mode: directDomUpdatesMode,
+ container: null as HTMLElement | null,
+ lastSize: null as number | null,
+ // Keyed by the element itself so a remounted node (same key, new DOM
+ // node — e.g. when `enabled` is toggled off then on) is treated as fresh
+ // and gets its style written.
+ lastPositions: new WeakMap(),
+ prevRange: null as {
+ startIndex: number
+ endIndex: number
+ isScrolling: boolean
+ } | null,
+ })
+ directRef.current.enabled = directDomUpdates
+ directRef.current.mode = directDomUpdatesMode
+
+ // Writes container size + item positions to the DOM. Idempotent — guarded
+ // by lastSize / lastPositions. Called from onChange (covers scroll-driven
+ // updates) and from a layout effect (covers post-render commits when refs
+ // have just registered new items in elementsCache).
+ const applyDirectStyles = (
+ instance: Virtualizer,
+ ) => {
+ const state = directRef.current
+ if (!state.enabled) return
+
+ const totalSize = instance.getTotalSize()
+ if (state.container && totalSize !== state.lastSize) {
+ state.lastSize = totalSize
+ const sizeAxis = instance.options.horizontal ? 'width' : 'height'
+ state.container.style[sizeAxis] = `${totalSize}px`
+ }
+
+ const horizontal = !!instance.options.horizontal
+ const useTransform = state.mode === 'transform'
+ const posAxis = horizontal ? 'left' : 'top'
+ const scrollMargin = instance.options.scrollMargin
+ const items = instance.getVirtualItems()
+ for (const item of items) {
+ const next = item.start - scrollMargin
+ const el = instance.elementsCache.get(item.key) as HTMLElement | undefined
+ if (!el) continue
+ if (state.lastPositions.get(el) === next) continue
+ state.lastPositions.set(el, next)
+ if (useTransform) {
+ el.style.transform = horizontal
+ ? `translate3d(${next}px, 0, 0)`
+ : `translate3d(0, ${next}px, 0)`
+ } else {
+ el.style[posAxis] = `${next}px`
+ }
+ }
+ }
+
const resolvedOptions: VirtualizerOptions = {
...options,
onChange: (instance, sync) => {
- if (useFlushSync && sync) {
- flushSync(rerender)
- } else {
- rerender()
+ const state = directRef.current
+ let shouldRerender = true
+
+ if (state.enabled) {
+ applyDirectStyles(instance)
+
+ // Only re-render on range / isScrolling changes
+ const range = instance.range
+ const prev = state.prevRange
+ shouldRerender =
+ !prev ||
+ prev.isScrolling !== instance.isScrolling ||
+ prev.startIndex !== range?.startIndex ||
+ prev.endIndex !== range?.endIndex
+ if (shouldRerender) {
+ state.prevRange = range
+ ? {
+ startIndex: range.startIndex,
+ endIndex: range.endIndex,
+ isScrolling: instance.isScrolling,
+ }
+ : null
+ }
+ }
+
+ if (shouldRerender) {
+ if (useFlushSync && sync) {
+ flushSync(rerender)
+ } else {
+ rerender()
+ }
}
+
options.onChange?.(instance, sync)
},
}
- const [instance] = React.useState(
- () => new Virtualizer(resolvedOptions),
- )
+ const [instance] = React.useState(() => {
+ const v = new Virtualizer(resolvedOptions)
+ return Object.assign(v, {
+ containerRef: (node: HTMLElement | null) => {
+ const state = directRef.current
+ state.container = node
+ state.lastSize = null
+ if (node && state.enabled) {
+ const total = v.getTotalSize()
+ state.lastSize = total
+ const axis = v.options.horizontal ? 'width' : 'height'
+ node.style[axis] = `${total}px`
+ }
+ },
+ })
+ })
instance.setOptions(resolvedOptions)
@@ -61,6 +208,13 @@ function useVirtualizerBase<
return instance._willUpdate()
})
+ // After every render commit, newly mounted item refs have registered in
+ // elementsCache; write their positions to the DOM so the user doesn't see
+ // them at (0, 0) until the next onChange.
+ useIsomorphicLayoutEffect(() => {
+ applyDirectStyles(instance)
+ })
+
return instance
}
@@ -72,7 +226,7 @@ export function useVirtualizer<
ReactVirtualizerOptions,
'observeElementRect' | 'observeElementOffset' | 'scrollToFn'
>,
-): Virtualizer {
+): ReactVirtualizer {
return useVirtualizerBase({
observeElementRect: observeElementRect,
observeElementOffset: observeElementOffset,
@@ -89,7 +243,7 @@ export function useWindowVirtualizer(
| 'observeElementOffset'
| 'scrollToFn'
>,
-): Virtualizer {
+): ReactVirtualizer {
return useVirtualizerBase({
getScrollElement: () => (typeof document !== 'undefined' ? window : null),
observeElementRect: observeWindowRect,
diff --git a/packages/solid-virtual/CHANGELOG.md b/packages/solid-virtual/CHANGELOG.md
index 709e9dee..90f09761 100644
--- a/packages/solid-virtual/CHANGELOG.md
+++ b/packages/solid-virtual/CHANGELOG.md
@@ -1,5 +1,12 @@
# @tanstack/solid-virtual
+## 3.13.27
+
+### Patch Changes
+
+- Updated dependencies [[`c746841`](https://github.com/TanStack/virtual/commit/c7468416354c203cd7cc952da5997073394224fb)]:
+ - @tanstack/virtual-core@3.16.1
+
## 3.13.26
### Patch Changes
diff --git a/packages/solid-virtual/package.json b/packages/solid-virtual/package.json
index 14082986..3fc2318f 100644
--- a/packages/solid-virtual/package.json
+++ b/packages/solid-virtual/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/solid-virtual",
- "version": "3.13.26",
+ "version": "3.13.27",
"description": "Headless UI for virtualizing scrollable elements in Solid",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/svelte-virtual/CHANGELOG.md b/packages/svelte-virtual/CHANGELOG.md
index f52bee0c..5bc82c7d 100644
--- a/packages/svelte-virtual/CHANGELOG.md
+++ b/packages/svelte-virtual/CHANGELOG.md
@@ -1,5 +1,12 @@
# @tanstack/svelte-virtual
+## 3.13.27
+
+### Patch Changes
+
+- Updated dependencies [[`c746841`](https://github.com/TanStack/virtual/commit/c7468416354c203cd7cc952da5997073394224fb)]:
+ - @tanstack/virtual-core@3.16.1
+
## 3.13.26
### Patch Changes
diff --git a/packages/svelte-virtual/package.json b/packages/svelte-virtual/package.json
index 3d74900a..031a4878 100644
--- a/packages/svelte-virtual/package.json
+++ b/packages/svelte-virtual/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/svelte-virtual",
- "version": "3.13.26",
+ "version": "3.13.27",
"description": "Headless UI for virtualizing scrollable elements in Svelte",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/virtual-core/CHANGELOG.md b/packages/virtual-core/CHANGELOG.md
index 569a0733..ef19da1f 100644
--- a/packages/virtual-core/CHANGELOG.md
+++ b/packages/virtual-core/CHANGELOG.md
@@ -1,5 +1,13 @@
# @tanstack/virtual-core
+## 3.16.1
+
+### Patch Changes
+
+- Eagerly adjust scrollOffset on prepend to prevent one-frame jump with anchorTo: 'end' ([#1176](https://github.com/TanStack/virtual/pull/1176))
+
+ When items are prepended with `anchorTo: 'end'` and dynamic sizes, the virtualizer would compute the wrong visible range for one frame (using stale estimate-based positions) and then correct in the next frame via `_willUpdate`, producing a visible jump. This fix eagerly adjusts `scrollOffset` in `setOptions` during the render pass so `calculateRange`/`getVirtualItems` return the correct items immediately.
+
## 3.16.0
### Minor Changes
diff --git a/packages/virtual-core/package.json b/packages/virtual-core/package.json
index fc9f4342..0529ac37 100644
--- a/packages/virtual-core/package.json
+++ b/packages/virtual-core/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/virtual-core",
- "version": "3.16.0",
+ "version": "3.16.1",
"description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/packages/virtual-core/src/index.ts b/packages/virtual-core/src/index.ts
index 7890df33..29b36f99 100644
--- a/packages/virtual-core/src/index.ts
+++ b/packages/virtual-core/src/index.ts
@@ -365,6 +365,7 @@ type PendingScrollAnchor = [
key: Key | null,
offset: number,
followOnAppend: ScrollBehavior | null,
+ anchorDelta: number,
]
export class Virtualizer<
@@ -535,6 +536,7 @@ export class Virtualizer<
| undefined
let anchor: [Key, number] | null = null
let followOnAppend: ScrollBehavior | null = null
+ let edgeKeysChanged = false
if (
prevOptions !== undefined &&
@@ -564,6 +566,7 @@ export class Virtualizer<
merged.getItemKey(nextCount - 1) !== prevLastKey))
if (didEdgeKeysChange) {
+ edgeKeysChanged = true
const item =
prevCount > 0
? (this.getVirtualItemForOffset(this.getScrollOffset()) ??
@@ -592,11 +595,51 @@ export class Virtualizer<
this.options = merged
- if (anchor || followOnAppend) {
+ // When edge keys changed (prepend, trim, reorder, etc.) the key→index
+ // mapping has shifted. Force a full measurement rebuild so the anchor
+ // resolution below reads positions from the new layout, not the stale
+ // memoised cache. Without this, a stable `getItemKey` reference +
+ // unchanged `count` would let getMeasurements() return the old layout.
+ if (edgeKeysChanged) {
+ this.pendingMin = 0
+ this.itemSizeCacheVersion++
+ }
+
+ // Eagerly adjust scrollOffset so the virtualizer computes the correct
+ // visible range during the current render pass — before _willUpdate
+ // syncs the DOM scroll position in a layout effect. Without this,
+ // the virtualizer would render the wrong items for one frame (the
+ // estimate-based positions are stale) and then correct in the next
+ // frame, producing a visible "jump" on prepend with dynamic sizes.
+ let anchorResolved = false
+ let anchorDelta = 0
+ if (anchor && this.scrollOffset !== null) {
+ const [anchorKey, anchorOffset] = anchor
+ const newMeasurements = this.getMeasurements()
+ const { count, getItemKey } = this.options
+ let idx = 0
+ while (idx < count && getItemKey(idx) !== anchorKey) {
+ idx++
+ }
+ if (idx < count) {
+ const anchorItem = newMeasurements[idx]
+ if (anchorItem) {
+ const newOffset = anchorItem.start + anchorOffset
+ if (newOffset !== this.scrollOffset) {
+ anchorDelta = newOffset - this.scrollOffset
+ this.scrollOffset = newOffset
+ anchorResolved = true
+ }
+ }
+ }
+ }
+
+ if (anchorResolved || followOnAppend) {
this.pendingScrollAnchor = [
- anchor?.[0] ?? null,
- anchor?.[1] ?? 0,
+ anchorResolved ? anchor![0] : null,
+ anchorResolved ? anchor![1] : 0,
followOnAppend,
+ anchorDelta,
]
}
}
@@ -798,22 +841,30 @@ export class Virtualizer<
this.pendingScrollAnchor = null
if (anchor && this.scrollElement && this.options.enabled) {
- const [key, offset, followOnAppend] = anchor
-
- if (key !== null) {
- const { count, getItemKey } = this.options
- let index = 0
- while (index < count && getItemKey(index) !== key) {
- index++
- }
-
- const item = index < count ? this.getMeasurements()[index] : undefined
- if (item) {
- const delta = item.start + offset - this.getScrollOffset()
-
- if (!approxEqual(delta, 0)) {
- this.applyScrollAdjustment(delta)
+ const [key, _offset, followOnAppend, anchorDelta] = anchor
+
+ if (key !== null && !followOnAppend) {
+ // scrollOffset was eagerly adjusted in setOptions so the
+ // virtualizer already computed the correct range during render.
+ // Now sync the browser's actual scroll position to match.
+ // Skip when followOnAppend is set — scrollToEnd will handle it.
+ //
+ // On iOS WebKit, writing scrollTop during touch/momentum cancels
+ // the in-flight scroll. Defer the DOM sync the same way
+ // applyScrollAdjustment does — accumulate the delta and let
+ // _flushIosDeferredIfReady handle it once the scroll settles.
+ if (
+ isIOSWebKit() &&
+ (this.isScrolling || this._iosTouching || this._iosJustTouchEnded)
+ ) {
+ if (anchorDelta !== 0) {
+ this._iosDeferredAdjustment += anchorDelta
}
+ } else {
+ this._scrollToOffset(this.getScrollOffset(), {
+ adjustments: undefined,
+ behavior: undefined,
+ })
}
}
diff --git a/packages/virtual-core/tests/index.test.ts b/packages/virtual-core/tests/index.test.ts
index e57119a1..0dc72977 100644
--- a/packages/virtual-core/tests/index.test.ts
+++ b/packages/virtual-core/tests/index.test.ts
@@ -2275,8 +2275,8 @@ test('anchorTo:end keeps visible content stable when older items are prepended',
expect(scrollToFn).toHaveBeenCalledTimes(1)
const [offset, options] = scrollToFn.mock.calls[0]!
- expect(offset).toBe(100)
- expect(options.adjustments).toBe(100)
+ expect(offset).toBe(200)
+ expect(options.adjustments).toBeUndefined()
})
test('anchorTo:end does not yank a scrolled-up user when items append', () => {
diff --git a/packages/vue-virtual/CHANGELOG.md b/packages/vue-virtual/CHANGELOG.md
index 45229076..4cbe050b 100644
--- a/packages/vue-virtual/CHANGELOG.md
+++ b/packages/vue-virtual/CHANGELOG.md
@@ -1,5 +1,12 @@
# @tanstack/vue-virtual
+## 3.13.27
+
+### Patch Changes
+
+- Updated dependencies [[`c746841`](https://github.com/TanStack/virtual/commit/c7468416354c203cd7cc952da5997073394224fb)]:
+ - @tanstack/virtual-core@3.16.1
+
## 3.13.26
### Patch Changes
diff --git a/packages/vue-virtual/package.json b/packages/vue-virtual/package.json
index d16e3d51..250545b9 100644
--- a/packages/vue-virtual/package.json
+++ b/packages/vue-virtual/package.json
@@ -1,6 +1,6 @@
{
"name": "@tanstack/vue-virtual",
- "version": "3.13.26",
+ "version": "3.13.27",
"description": "Headless UI for virtualizing scrollable elements in Vue",
"author": "Tanner Linsley",
"license": "MIT",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 28e50fe8..d43e2cfc 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -142,7 +142,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -194,7 +194,7 @@ importers:
specifier: ^19.0.0
version: 19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.20(@angular/animations@19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -249,7 +249,7 @@ importers:
specifier: 5.80.7
version: 5.80.7(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -301,7 +301,7 @@ importers:
specifier: ^19.0.0
version: 19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.20(@angular/animations@19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -353,7 +353,7 @@ importers:
specifier: ^19.0.0
version: 19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.20(@angular/animations@19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -408,7 +408,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -466,7 +466,7 @@ importers:
specifier: 8.21.3
version: 8.21.3(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -518,7 +518,7 @@ importers:
specifier: ^19.0.0
version: 19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.20(@angular/animations@19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -570,7 +570,7 @@ importers:
specifier: ^19.0.0
version: 19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(@angular/platform-browser@19.2.20(@angular/animations@19.2.20(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(@angular/common@19.2.20(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1))(rxjs@7.8.2))(@angular/core@19.2.20(rxjs@7.8.2)(zone.js@0.15.1)))(rxjs@7.8.2)
'@tanstack/angular-virtual':
- specifier: ^5.0.2
+ specifier: ^5.0.3
version: link:../../../packages/angular-virtual
rxjs:
specifier: ^7.8.2
@@ -601,10 +601,10 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/lit-virtual':
- specifier: ^3.13.27
+ specifier: ^3.13.28
version: link:../../../packages/lit-virtual
'@tanstack/virtual-core':
- specifier: ^3.16.0
+ specifier: ^3.16.1
version: link:../../../packages/virtual-core
lit:
specifier: ^3.3.0
@@ -626,10 +626,10 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/lit-virtual':
- specifier: ^3.13.27
+ specifier: ^3.13.28
version: link:../../../packages/lit-virtual
'@tanstack/virtual-core':
- specifier: ^3.16.0
+ specifier: ^3.16.1
version: link:../../../packages/virtual-core
lit:
specifier: ^3.3.0
@@ -648,7 +648,7 @@ importers:
examples/react/chat:
dependencies:
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -679,7 +679,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -710,7 +710,7 @@ importers:
examples/react/fixed:
dependencies:
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -744,7 +744,7 @@ importers:
specifier: ^5.80.7
version: 5.90.5(react@18.3.1)
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -769,7 +769,7 @@ importers:
examples/react/padding:
dependencies:
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -797,7 +797,7 @@ importers:
specifier: ^0.0.7
version: 0.0.7
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -831,7 +831,7 @@ importers:
specifier: ^25.1.1
version: 25.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -856,7 +856,7 @@ importers:
examples/react/smooth-scroll:
dependencies:
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -884,7 +884,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
lodash:
specifier: ^4.17.21
@@ -921,7 +921,7 @@ importers:
specifier: ^8.21.3
version: 8.21.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -946,7 +946,7 @@ importers:
examples/react/variable:
dependencies:
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -971,7 +971,7 @@ importers:
examples/react/window:
dependencies:
'@tanstack/react-virtual':
- specifier: ^3.13.26
+ specifier: ^3.14.1
version: link:../../../packages/react-virtual
react:
specifier: ^18.3.1
@@ -1005,7 +1005,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/svelte-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/svelte-virtual
devDependencies:
'@sveltejs/vite-plugin-svelte':
@@ -1033,7 +1033,7 @@ importers:
examples/svelte/fixed:
dependencies:
'@tanstack/svelte-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/svelte-virtual
devDependencies:
'@sveltejs/vite-plugin-svelte':
@@ -1064,7 +1064,7 @@ importers:
specifier: ^5.80.7
version: 5.90.2(svelte@4.2.20)
'@tanstack/svelte-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/svelte-virtual
devDependencies:
'@sveltejs/vite-plugin-svelte':
@@ -1095,7 +1095,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/svelte-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/svelte-virtual
devDependencies:
'@sveltejs/vite-plugin-svelte':
@@ -1126,7 +1126,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/svelte-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/svelte-virtual
lodash:
specifier: ^4.17.21
@@ -1163,7 +1163,7 @@ importers:
specifier: ^8.21.3
version: 8.21.3(svelte@4.2.20)
'@tanstack/svelte-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/svelte-virtual
devDependencies:
'@sveltejs/vite-plugin-svelte':
@@ -1194,7 +1194,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16
@@ -1219,7 +1219,7 @@ importers:
examples/vue/fixed:
dependencies:
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16
@@ -1247,7 +1247,7 @@ importers:
specifier: ^5.80.7
version: 5.90.5(vue@3.5.22(typescript@5.6.3))
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16
@@ -1272,7 +1272,7 @@ importers:
examples/vue/padding:
dependencies:
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16
@@ -1297,7 +1297,7 @@ importers:
examples/vue/scroll-padding:
dependencies:
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
'@vueuse/core':
specifier: ^12.8.2
@@ -1325,7 +1325,7 @@ importers:
examples/vue/smooth-scroll:
dependencies:
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16
@@ -1353,7 +1353,7 @@ importers:
specifier: ^8.4.1
version: 8.4.1
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
lodash:
specifier: ^4.17.21
@@ -1390,7 +1390,7 @@ importers:
specifier: ^8.21.3
version: 8.21.3(vue@3.5.22(typescript@5.6.3))
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16
@@ -1415,7 +1415,7 @@ importers:
examples/vue/variable:
dependencies:
'@tanstack/vue-virtual':
- specifier: ^3.13.26
+ specifier: ^3.13.27
version: link:../../../packages/vue-virtual
vue:
specifier: ^3.5.16