Decorative background gradient
Back to Blog
TanStack Table ReactReact Table VirtualizationFast Large Dataset Rendering

TanStack Table React Virtualization: Fast Large Dataset Rendering

Render tens of thousands of rows without jank using TanStack Table v8 and react-virtual — infinite scroll, custom filters, and real performance gains.

TanStack Table React Virtualization: Fast Large Dataset Rendering

Rendering a table with a few hundred rows is trivial. Rendering one with 50,000+ rows — while keeping sorting, filtering, and smooth scrolling — is a completely different problem. TanStack Table gives you the headless logic; TanStack Virtual gives you the rendering performance. Together they let you build a data table that stays fast regardless of dataset size.

This guide builds a virtualized, infinitely-scrollable data table step by step.

Step 1: Set Up a Headless TanStack Table

TanStack Table doesn't render any markup — you define columns and it hands you row/column models to render however you want.

tsx

At this point rows could be 50 or 50,000 items — TanStack Table doesn't care, because it never touches the DOM.

Step 2: Virtualize the Rows

@tanstack/react-virtual only mounts the DOM nodes that are actually visible in the scroll container, plus a small overscan buffer.

tsx

The key mechanics: getTotalSize() gives the virtualizer's computed total scrollable height, and each row is absolutely positioned via translateY to its calculated offset. Only the rows returned by getVirtualItems() — typically 15-25 depending on viewport height — actually exist in the DOM at any moment, even if rows.length is 50,000.

Step 3: Add Infinite Scroll for Server-Paginated Data

Virtualization handles rendering; infinite scroll handles fetching more data as the user approaches the bottom. Combine the virtualizer's scroll position with useInfiniteQuery (TanStack Query):

tsx
tsx

This fetches the next 100-row page once the user scrolls within 20 rows of the currently loaded data, so new rows arrive before the user actually hits the bottom.

Step 4: Add Custom Filters Without Breaking Virtualization

Filtering happens entirely in TanStack Table's state layer — the virtualizer never needs to know about it.

tsx

Because rowVirtualizer is built from table.getRowModel().rows.length, filtering the underlying data automatically shrinks the virtualized row count — no manual synchronization required.

Performance in Practice

On a 50,000-row dataset, an un-virtualized table renders 50,000+ DOM nodes upfront — first paint alone can take several seconds and scrolling drops to single-digit frame rates. With virtualization, only ~20-30 rows ever exist in the DOM at once regardless of dataset size, so first paint stays under 100ms and scrolling holds a smooth 60fps because the browser is never asked to lay out more than a screenful of rows.

Common Pitfall: Row Height Drift Causes Scroll Jumps

If your estimateSize is a fixed value but actual row content varies in height (wrapped text, conditional badges), the virtualizer's positions will be slightly wrong until it measures real DOM heights. Always attach ref={rowVirtualizer.measureElement} to each row — it corrects the estimate after the first render and eliminates the jump.

Key Takeaways

TanStack Table's headless architecture is what makes true virtualization possible — it never dictates markup, so you can hand its row model straight to @tanstack/react-virtual and only render what's on screen. Layer infinite scroll on top with useInfiniteQuery, keep filtering in TanStack Table's state (the virtualizer picks it up automatically), and always measure real row heights to avoid scroll jitter.

Frequently Asked Questions

Is TanStack Table the same as react-table?

TanStack Table v8 is the successor to react-table v7, rebuilt to be framework-agnostic (React, Vue, Solid, Svelte adapters) and fully headless — it ships no markup or CSS, only table logic and state.

Why do I need a separate virtualization library?

TanStack Table computes rows, sorting, filtering, and pagination state, but it doesn't touch the DOM. Rendering 50,000 <tr> elements at once will freeze the browser regardless of how efficient the table logic is. @tanstack/react-virtual solves the rendering half by only mounting the rows currently in the viewport.

Can I combine virtualization with sorting and filtering?

Yes. Apply sorting/filtering through TanStack Table's state as normal — call table.getRowModel().rows to get the already sorted/filtered rows, then pass that array's length to the virtualizer. The virtualizer doesn't need to know about sorting or filtering at all.

How do I handle variable-height rows in a virtualized table?

Use the virtualizer's measureElement ref callback on each row instead of a fixed estimateSize. It measures actual rendered height after mount and recalculates virtual item positions, which prevents scroll position from jumping when row heights vary.

Working on something similar? Take a look at my services and case studies, or book a free call to talk about your idea.

Related Articles

Caching Strategies and Cache Invalidation — The Complete Guide
CachingSystem DesignPerformance

Caching Strategies and Cache Invalidation — The Complete Guide

A practical guide to caching strategies (cache-aside, write-through, write-behind) and the cache invalidation techniques that keep them from serving stale data.

September 8, 2026Read more →
Database Indexing and Read Replicas — A Practical Guide
DatabasePostgreSQLSystem Design

Database Indexing and Read Replicas — A Practical Guide

How to choose the right database indexes, avoid the ones that quietly hurt write performance, and scale reads with replicas without introducing replication lag bugs.

September 8, 2026Read more →
Load Balancing and Stateless Service Design — A Practical Guide
System DesignLoad BalancingScalability

Load Balancing and Stateless Service Design — A Practical Guide

How load balancers distribute traffic, why stateless services are what actually makes horizontal scaling work, and how to fix the sticky-session traps that quietly reintroduce state.

September 8, 2026Read more →
Session Stores and Database Connection Pooling Explained
BackendRedisDatabase

Session Stores and Database Connection Pooling Explained

Why in-memory sessions break horizontally scaled apps, how to move session state to Redis correctly, and how connection pooling keeps your database from falling over under concurrent load.

September 8, 2026Read more →
Vertical vs Horizontal Scaling: How to Choose and Implement Each
System DesignScalabilityArchitecture

Vertical vs Horizontal Scaling: How to Choose and Implement Each

A practical comparison of vertical and horizontal scaling — what each actually fixes, where each breaks down, and the architecture changes horizontal scaling requires that most guides skip.

September 8, 2026Read more →
AI Agent Guardrails and Safety — Preventing Prompt Injection and Runaway Actions
Ai Agent SafetyPrompt Injection DefenseAgent Guardrails

AI Agent Guardrails and Safety — Preventing Prompt Injection and Runaway Actions

Build practical guardrails for AI agents — prompt injection defenses, destructive-action confirmation, iteration caps, and permission scoping.

September 7, 2026Read more →

Trending Topics