Headless virtualization

TanStackVirtual

Massive scroll surfaces without massive DOM.

Virtual calculates the visible window for long lists, grids, and scroll containers so your app can keep the markup, layout, and design while rendering only the work the user can see.

Total DownloadsWeekly DownloadsGitHub Stars

The most popular and most used virtualization engine for modern web apps.

Read the docs

Visible window

render the viewport, not the dataset

Measured sizing

fixed, variable, dynamic rows

Headless scroll

own the container, markup, and styles

10,000 rows / 8 mounted / 6 visible
Manual

scroll API

virtualizer.scrollToIndex(180)

range

Row 18034px measured
Row 18152px measured
Row 18242px measured
Row 18366px measured
Row 18438px measured
Row 18558px measured
Row 18646px measured
Row 18774px measured

Why Virtual

Performance is a layout problem before it is a rendering problem.

Virtualization is not just fewer nodes. It is scroll math, measurement, overscan, dynamic content, and container ownership. Virtual gives you those primitives without forcing a visual component on top.

The DOM stays small while the list stays huge.

Virtual calculates the visible range, pads the scroll space, and lets you render only the items the user can actually see.

Measurement handles real content.

Use fixed sizes when you can, measured dynamic sizes when content varies, and overscan to keep fast scrolling smooth.

Scroll containers stay product-owned.

Window scrolling, element scrolling, grids, lanes, sticky UI, and custom markup remain your responsibility and your freedom.

It composes with the rest of the stack.

Pair Virtual with Table for giant grids, Query for paged data, Router for URL state, or your own renderer for anything else.

1

Count

Tell the virtualizer how many things exist, even if most of them are not mounted.

2

Estimate

Start from a stable size estimate so the scroll range is known immediately.

3

Measure

Let dynamic items report real sizes as content loads or expands.

4

Render

Map virtual items to your own absolutely positioned rows, cells, or cards.

Virtualizer lifecycle

Keep the scroll range honest while the DOM stays lean.

Estimate first, measure when needed, then render virtual items into your own row, card, cell, or lane components. The API is small because the layout remains yours.

AI chat virtualization

Chat scroll is backwards, streaming, and constantly resizing.

Chat, agents, copilots, logs, and support inboxes need end anchoring, stable prepends, append-follow, and a reliable way to jump back to the latest turn. Virtual now models those behaviors as scroll primitives instead of app-specific bookkeeping.

anchorTo

'end' keeps the latest edge stable

followOnAppend

follow only when already pinned

scrollToEnd

wire a Latest control to the API

measureElement

let streamed bubbles grow naturally

6 messages / 5 mounted / 4 visible

anchorTo: 'end'

272px from end / reading history

user

Can you summarize the alerts from the last deploy?

assistant

Three services reported higher latency, but only search crossed the user-visible threshold. I would start with the cache miss spike at 14:42.

tooltool result

query deploy_events --service search --window 30m

assistant

The slow requests line up with a schema warmup path. The good news: the regression is isolated and the route recovered after the cache filled.

user

Draft the follow-up for the incident channel.

Scroll surfaces

Lists, lanes, and grids all share the same windowing idea.

A virtualizer is a calculation layer. Whether the output becomes a vertical feed, a horizontal timeline, or a two-dimensional grid, the product keeps control of the actual experience.

Vertical lists

Feeds, menus, logs, timelines, search results, and long admin indexes.

Horizontal lanes

Calendars, kanban lanes, timelines, image strips, and dense inspectors.

Grid surfaces

Rows and columns that need windowing without adopting a canned grid UI.

Framework adapters

The same virtual math across UI runtimes.

Use the adapter that fits your framework, or work from the core. The virtual range, measurements, and scroll behavior stay focused on the data and container instead of the renderer.

ReactVueSolidSvelteLitAngular
Just a quick look...
import { useVirtualizer } from '@tanstack/react-virtual'

const rowVirtualizer = useVirtualizer({
  count: 1000,
  getScrollElement: () => parentRef.current,
  estimateSize: () => 36,
})
// Map virtual rows to your UI
import { useVirtualizer } from '@tanstack/react-virtual'

const rowVirtualizer = useVirtualizer({
  count: 1000,
  getScrollElement: () => parentRef.current,
  estimateSize: () => 36,
})
// Map virtual rows to your UI

Field notes

Smooth scrolling is table stakes. Owning the surface is the point.

The existing copy had the right spirit: a tiny API for vertical, horizontal, and grid-style virtualization, with all the design control left in your hands.

Loved by Developers

See what teams are saying

"We chose TanStack Virtual for our virtualization needs - it handles our massive lists without breaking a sweat."

Evan Bacon
@Baconbrix · Expo

"TanStack Virtual is the answer when you need to render thousands of rows without destroying performance. Headless, flexible, and just works."

Developer Review
Community ·

"For anyone dealing with large datasets in React, TanStack Virtual is a must. The row virtualizer alone saved our app."

Community Developer
GitHub Discussion ·

"We chose TanStack Virtual for our virtualization needs - it handles our massive lists without breaking a sweat."

Evan Bacon
@Baconbrix · Expo

"TanStack Virtual is the answer when you need to render thousands of rows without destroying performance. Headless, flexible, and just works."

Developer Review
Community ·

"For anyone dealing with large datasets in React, TanStack Virtual is a must. The row virtualizer alone saved our app."

Community Developer
GitHub Discussion ·

Open source ecosystem

Virtual is small because the community keeps it sharp.

Maintainers, adapters, examples, partners, and GitHub sponsors keep the virtualization core close to real scrolling problems.

GitHub Sponsors

Wow, you've come a long way!
Only one thing left to do...