TanStack Virtual: the counting engine behind long lists, and everything it leaves to you
🤖 Headless UI for Virtualizing Large Element Lists in JS/TS, React, Solid, Vue and Svelte
At a glance
- What is it?
- A headless virtualizer with one hook per framework, a core package that versions ahead of its adapters, and a README that promises 60FPS without naming an option. Worth reading before you drop it into a table.
- Who is it for?
- Adopt TanStack Virtual when your list is long enough that rendering every row hurts and your team already owns the markup, because headless means the scroller, the row and the empty state are your code. Skip it if you wanted a ready made list component.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- TanStack/virtual7,198 ★ · +79
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| TanStack/virtual | 7.1k | 7.2k |
79 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
One hook per framework, with the measuring kept in a core package
The repository calls TanStack Virtual headless UI for virtualizing large element lists in JS/TS, React, Solid, Vue and Svelte, and the README calls it a headless, framework-agnostic virtualization library for rendering massive lists, grids and tables at 60FPS while you keep full control over markup and styles. Both sentences describe the same trade. One hook or function per framework does the measuring and the range math, and everything visible in the browser is yours to write. The README says a single hook or function covers vertical, horizontal and grid layouts. So the package hands you a scroll container, an item range and a total count. It does not hand you a list component, a row template, a loading row or a scrollbar. That is the point for a team with its own design system, and a second project for a team expecting a drop in component.
Core 3.17.11 shipped ahead of the Vue and Svelte adapters at 3.13.39
Three releases landed on 2026-11-01, and they do not share a version line. `@tanstack/virtual-core` went out at 3.19.10, while `@tanstack/solid-virtual` went out at 3.13.52 and `@tanstack/marko-virtual` at 3.16.11. That gap is the fact that matters when you pin dependencies: an adapter version does not tell you which core version you resolved, so one lockfile can hold two version lines at once. The README badges point at `@tanstack/virtual-core` on npmjs and at a bundlephobia result for `@tanstack/virtual-core@latest`, which is the hint that core is the package to watch for size. Before bumping an adapter inside a large app, read the resolved core range, because a core jump can move measurement behavior under rows you already tuned. The README carries no compatibility table for those pairings.
The root package is private and refuses anything but pnpm 11.9.0
The repository root package.json is named root, marked private, typed as module, and it pins its package manager two ways. `packageManager` reads `[email protected]` and `engines` requires `pnpm >=11.9.0`, with `pnpm-workspace.yaml` and `pnpm-lock.yaml` at the root and a `.nvmrc` for the Node side. Nothing in the tree suggests npm or yarn work is supported. The exact pin means a pnpm 10 checkout is not the intended setup. The private flag has a second effect: the root is never publishable, so only the packages under `packages/` reach npm.
No install line in the README, so setup lives on the docs site and in CONTRIBUTING.md
The README prints no install command for the published packages. It points readers to `https://tanstack.com/virtual` for docs and to `CONTRIBUTING.md` for setup instructions, and it links the npm page and the bundlephobia result for `@tanstack/virtual-core`. The commands a contributor can actually copy come from the scripts block of the root package.json:
pnpm run build:all
pnpm run dev
pnpm run test:ci
pnpm run verify-examples`dev` is `pnpm run watch`, which builds everything and then watches. `test:ci` is the wide one: nx runs the targets test:sherif, test:knip, test:docs, test:eslint, test:lib, test:e2e, test:types, test:build and build. Two of those names are files in `scripts/`, reached through `test:docs` and `verify-examples`. The toolchain requirements are declared rather than written out:
{
"packageManager": "[email protected]",
"engines": {
"pnpm": ">=11.9.0"
},
"type": "module"
}For a consumer rather than a contributor, the first stop is the docs site, because the README names no option and no import path.
Dynamic and measured sizing are promised, but no option name appears anywhere
Four bullets carry the whole pitch: framework-agnostic and headless, one hook or function for vertical, horizontal and grid layouts, lightweight at 10 to 15kb with dynamic and measured sizing support, and smooth 60FPS scrolling with sticky items and window-scrolling utilities. Read them as a feature list, not as an API. The README never names the option that turns measurement on, never says whether rows are measured before paint or after, and never defines what dynamic sizing expects from your data. It also never says which package the 10 to 15kb figure covers, and the bundlephobia badge it links is scoped to `@tanstack/virtual-core@latest` rather than to any adapter. So the README cannot tell you whether measured sizing covers your case. Read `https://tanstack.com/virtual` before you commit, and expect to supply row heights yourself on the paths it does not cover.
The 60FPS figure has no test conditions attached to it
The same sentence that promises smooth 60FPS scrolling appears above a `benchmarks/` directory that sits in the repository alongside `docs/` and `media/`. The README gives no command for running those benchmarks, no row counts, no item heights, no device and no browser, so the directory cannot be read as evidence for the claim above it. Treat 60FPS as the project's own assertion, not as a measurement you can rely on. The practical consequence shows up on the first heavy row set: virtualization pays off only when your item heights are cheap for the library to know. If your rows are images, wrapped text or anything that resizes after render, the fast path and the slow path diverge, and nothing in the README tells you which side of that line the 60FPS claim came from. A team shipping a live table should measure its own scroll on real data before believing the number.
Changesets, knip and sherif decide whether a pull request lands
The repository gates contributions with its own tooling. `.changeset/` is present and `changeset:version` runs `changeset version && pnpm install --no-frozen-lockfile && pnpm format`, followed by `changeset:publish`. `test:knip` runs knip against `knip.json`, and `test:sherif` runs sherif, which is why the target list in `test:ci` includes both. Formatting is prettier through the `format` script, with `prettier.config.js`, `.prettierignore` and `eslint.config.js` at the root. Two link checkers run over the docs: `test:docs` and `verify-links` both reach `node scripts/verify-links.ts`, and `verify-examples` reaches `node scripts/verify-examples.ts`. Help and discussion live on GitHub Discussions and a Discord invite, and the last push landed on 2026-11-01, the same day as the releases above. The license is MIT and the code is TypeScript on the main branch.
Editorial conclusion
Adopt TanStack Virtual when your list is long enough that rendering every row hurts and your team already owns the markup, because headless means the scroller, the row and the empty state are your code. Skip it if you wanted a ready made list component. Before you commit, open https://tanstack.com/virtual to confirm the measured sizing options exist for your case, and read your lockfile to see which @tanstack/virtual-core version your adapter actually resolved to, since the core and adapter version lines have moved apart.
Frequently asked questions
Which frameworks does TanStack Virtual claim to support?
The repository description names JS/TS, React, Solid, Vue and Svelte, and the README calls the library framework-agnostic with a single hook or function for vertical, horizontal and grid layouts. The examples directory holds angular, lit, marko, react, svelte and vue, with no solid example directory among them.
How large is the TanStack Virtual payload?
The README calls it lightweight at 10 to 15kb and links a bundlephobia result for @tanstack/virtual-core@latest, so that range is stated without saying which package or which framework adapter it measures. Your own bundle depends on the adapter and the bundler.
Where are the installation instructions for TanStack Virtual?
The README prints no install command. It links the docs at https://tanstack.com/virtual for the library and points to CONTRIBUTING.md for setup instructions in the repository itself, where the root package.json requires pnpm 11.9.0 or newer.
Does TanStack Virtual ship list components or only logic?
Only logic. The README frames it as headless and says you keep full control over markup and styles, so a scroll container, row markup and any loading or empty state are code you write yourself.
Can TanStack Virtual handle rows whose height changes at runtime?
The README claims dynamic and measured sizing support, but it names no option for enabling either one and does not say what your data has to provide. The docs at tanstack.com/virtual are the only place the behaviour is described.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tanstack-virtual)Star history chart for your README
[](https://hysenlabs.com/projects/tanstack-virtual)Was this useful?