Mastering React Window Virtualization
Learn how to build lightning-fast UIs that handle thousands of items without performance degradation. From basic list virtualization to advanced grid implementations, discover the techniques that power modern web applications.
Complete Tutorial Code
Follow along with the complete source code for this React Window virtualization tutorial. Includes four different examples with Next.js, TypeScript, and Tailwind CSS.
View on GitHubIntroduction
Modern web applications often need to display large datasets - think social media feeds, data tables, or file explorers with thousands of items. Rendering all these items at once creates a performance nightmare: slow initial loads, janky scrolling, and memory bloat that can crash browsers.
Virtualization solves this problem by rendering only the items visible in the viewport, plus a small buffer. This technique transforms applications that would otherwise be unusable with large datasets into smooth, responsive experiences that scale to millions of items.
The Performance Problem
Without virtualization, rendering a list of 10,000 items creates 10,000 DOM nodes immediately. Each node consumes memory and requires layout calculations, even if only 20 items are visible on screen. The browser struggles with this overhead, leading to:
Without Virtualization
With Virtualization
Understanding React Window
React Window is a lightweight virtualization library that provides components for efficiently rendering large lists and grids. Created by Brian Vaughn (React core team), it offers a simpler API than its predecessor react-virtualized while maintaining excellent performance.
The library works by calculating which items are visible based on the scroll position and container dimensions, then rendering only those items plus a small buffer for smooth scrolling.
import { List } from "react-window";
import { type RowComponentProps } from "react-window";
// Basic virtualized list
<List
rowComponent={RowComponent}
rowCount={10000} // Total number of items
rowHeight={25} // Height of each item
rowProps={{ items }}
/>Four Virtualization Patterns
Our tutorial demonstrates four essential virtualization patterns, each solving different use cases you'll encounter in real applications.
1. Fixed Height Lists
The simplest and most performant approach. When all items have the same height, React Window can calculate positions using simple math without measuring individual items.
// Perfect for simple lists like user names, tags, or menu items
function RowComponent({ index, names, style }: RowComponentProps<{ names: string[] }>) {
return (
<div className="flex items-center justify-between" style={style}>
{names[index]}
<div className="text-slate-500 text-xs">{`${index + 1} of ${names.length}`}</div>
</div>
);
}
<List
rowComponent={RowComponent}
rowCount={names.length}
rowHeight={25} // All items exactly 25px tall
rowProps={{ names }}
/>2. Variable Height Lists
When items have different but predictable heights, you can provide a function that returns the height for each item. This works well for hierarchical data or mixed content types.
// Different heights for different item types
function VariableRowComponent({ index, items, style }: RowComponentProps<{ items: Item[] }>) {
const item = items[index];
return (
<div className="flex items-center justify-between px-2" style={style}>
{item.type === "state" ? (
<div className="font-semibold text-blue-600">{item.state}</div>
) : (
<div className="text-sm">
<span className="font-medium">{item.city}</span>
<span className="text-gray-500 ml-2">{item.zip}</span>
</div>
)}
</div>
);
}
function rowHeight(index: number, { items }: { items: Item[] }) {
return items[index].type === "state" ? 30 : 25; // States taller than cities
}
<List
rowComponent={VariableRowComponent}
rowCount={items.length}
rowHeight={rowHeight}
rowProps={{ items }}
/>3. Dynamic Height Lists
The most complex but flexible approach. Heights are measured at runtime and can change dynamically. Essential for content like expandable cards, comments with varying text length, or rich media items.
// Heights measured and cached automatically using hooks
const { items, toggleExpanded } = useListState(initialItems);
function DynamicRowComponent({ index, items, style }: RowComponentProps<{ items: DynamicItem[] }>) {
const item = items[index];
return (
<DynamicRowComponent
key={item.id}
item={item}
onToggle={() => toggleExpanded(item.id)}
style={style}
/>
);
}
function rowHeight(index: number, { items }: { items: DynamicItem[] }) {
const item = items[index];
return item.expanded ? 120 : 60; // Expanded items are taller
}
<List
rowComponent={DynamicRowComponent}
rowCount={items.length}
rowHeight={rowHeight}
rowProps={{ items }}
/>4. Grid Virtualization
Two-dimensional virtualization for tabular data. Virtualizes both rows and columns, making it possible to display massive spreadsheets or data tables with millions of cells.
// Virtualized data grid
function CellComponent({ contacts, columnIndex, rowIndex, style }: CellComponentProps<{ contacts: Contact[] }>) {
const contact = contacts[rowIndex];
const content = contact[indexToColumn(columnIndex)];
return (
<div className="truncate border-r border-b border-gray-200 px-2 py-1 text-sm" style={style}>
{content}
</div>
);
}
<Grid
cellComponent={CellComponent}
cellProps={{ contacts }}
columnCount={COLUMNS.length}
columnWidth={columnWidth}
rowCount={contacts.length}
rowHeight={25}
/>Advanced Implementation Techniques
Scroll-to-Item Navigation
Programmatically scroll to specific items using refs and the `scrollToItem` method. Essential for search functionality, bookmarks, or navigation controls.
const listRef = useListRef(null);
const scrollToRow = () => {
const index = parseInt(scrollTarget, 10);
if (!isNaN(index) && index >= 0 && index < items.length) {
const list = listRef.current;
list?.scrollToRow({
align: "auto",
behavior: "auto",
index: index,
});
}
};
// Jump to specific items
<button onClick={scrollToRow}>
Scroll to Row
</button>
<List listRef={listRef} rowComponent={RowComponent} rowCount={items.length} rowHeight={25} rowProps={{ items }} />Dynamic Content with Auto-Sizing
For content that changes size dynamically, use ResizeObserver to detect size changes and update the virtualized list accordingly.
function DynamicRowComponent({ item, onToggle, style }: { item: DynamicItem; onToggle: () => void; style: React.CSSProperties }) {
return (
<div className="border-b border-gray-200 p-4" style={style}>
<div className="flex items-center justify-between">
<div>
<h3 className="font-medium">{item.title}</h3>
<p className="text-sm text-gray-500">{item.subtitle}</p>
</div>
<button onClick={onToggle} className="text-blue-500 hover:text-blue-700">
{item.expanded ? "Collapse" : "Expand"}
</button>
</div>
{item.expanded && (
<div className="mt-3 p-3 bg-gray-50 rounded">
<p className="text-sm">{item.description}</p>
</div>
)}
</div>
);
}TypeScript Integration
React Window provides excellent TypeScript support with proper type definitions for all components and their props.
interface RowComponentProps<T> {
index: number;
style: React.CSSProperties;
} & T;
interface Contact {
job_title: string;
first_name: string;
last_name: string;
email: string;
gender: string;
address: string;
city: string;
state: string;
zip: string;
timezone: string;
}
function RowComponent({ index, contacts, style }: RowComponentProps<{ contacts: Contact[] }>) {
const contact = contacts[index];
return (
<div style={style} className="px-4 py-2 border-b">
<div className="font-semibold">{contact.first_name} {contact.last_name}</div>
<div className="text-sm text-gray-600">{contact.email}</div>
</div>
);
}Performance Benefits
Memory Efficiency
Constant memory usage regardless of dataset size. Only visible items consume DOM memory.
Rendering Speed
Initial render time stays constant even with millions of items. No more loading spinners.
Smooth Scrolling
Buttery smooth 60fps scrolling through any amount of data. Perfect user experience.
Infinite Scalability
Handle datasets of any size without performance degradation. Scale to millions of items.
Getting Started
Ready to implement virtualization in your React application? Follow these steps to get the tutorial project running locally:
- 1Clone the repository:
git clone https://github.com/audoir/virtualization-tutorial.git - 2Install dependencies:
npm install - 3Start the development server:
npm run dev - 4Explore the examples:http://localhost:3000 - Interactive tutorial with all four examples
Learning Outcomes
By completing this tutorial, you will have gained practical experience with:
- • Understanding when and why to use virtualization
- • Implementing fixed height lists for maximum performance
- • Handling variable height content with predictable sizing
- • Managing dynamic height content with automatic measurement
- • Building virtualized grids for tabular data
- • Adding scroll-to-item navigation functionality
- • Integrating TypeScript for type-safe virtualization
- • Optimizing performance for large datasets
Real-World Applications
Virtualization is essential for many types of applications:
- • Social Media Feeds - Infinite scroll through thousands of posts
- • Data Tables - Spreadsheet-like interfaces with massive datasets
- • File Explorers - Browse directories with thousands of files
- • Chat Applications - Message history with years of conversations
- • E-commerce - Product catalogs with extensive inventories
- • Admin Dashboards - User lists, transaction logs, analytics data
Conclusion
React Window virtualization transforms the user experience for data-heavy applications. By rendering only visible items, you can create interfaces that feel instant and responsive regardless of dataset size.
The four patterns demonstrated in this tutorial cover the vast majority of virtualization use cases you'll encounter. Start with fixed height lists for simplicity, then progress to more advanced patterns as your requirements grow.
About the Author
Wayne Cheng is the founder and AI app developer at Audoir, LLC. Prior to founding Audoir, he worked as a hardware design engineer for Silicon Valley startups and an audio engineer for creative organizations. He holds an MSEE from UC Davis and a Music Technology degree from Foothill College.
Further Exploration
To deepen your understanding of React virtualization, explore the complete tutorial repository and experiment with different data types and layouts. Try implementing infinite scroll, search functionality, or custom item renderers to master these powerful techniques.
For more AI-powered development tools and tutorials, visit Audoir .