Hooks for virtualizing scrollable elements in React with support for rows, columns, and grids
npx @tessl/cli install tessl/npm-react-virtual@3.13.00
# React Virtual
1
2
React Virtual is a React hooks library that provides efficient virtualization capabilities for scrollable elements, enabling developers to render large lists and grids with optimal performance. The library offers a single headless hook (useVirtual) that supports row, column, and grid virtualization with flexible sizing options including fixed, variable, and dynamic measurements.
3
4
## Package Information
5
6
- **Package Name**: react-virtual
7
- **Package Type**: npm
8
- **Language**: JavaScript (with TypeScript support)
9
- **Installation**: `npm install react-virtual` or `yarn add react-virtual`
10
11
## Core Imports
12
13
```javascript
14
import { useVirtual } from "react-virtual";
15
```
16
17
For CommonJS:
18
19
```javascript
20
const { useVirtual } = require("react-virtual");
21
```
22
23
## Basic Usage
24
25
```javascript
26
import React from "react";
27
import { useVirtual } from "react-virtual";
28
29
function VirtualList() {
30
const parentRef = React.useRef();
31
32
const rowVirtualizer = useVirtual({
33
size: 10000,
34
parentRef: parentRef,
35
estimateSize: React.useCallback(() => 35, []),
36
});
37
38
return (
39
<div
40
ref={parentRef}
41
style={{
42
height: "200px",
43
width: "400px",
44
overflow: "auto",
45
}}
46
>
47
<div
48
style={{
49
height: `${rowVirtualizer.totalSize}px`,
50
width: "100%",
51
position: "relative",
52
}}
53
>
54
{rowVirtualizer.items.map((virtualRow) => (
55
<div
56
key={virtualRow.index}
57
style={{
58
position: "absolute",
59
top: 0,
60
left: 0,
61
width: "100%",
62
height: `${virtualRow.size}px`,
63
transform: `translateY(${virtualRow.start}px)`,
64
}}
65
>
66
Row {virtualRow.index}
67
</div>
68
))}
69
</div>
70
</div>
71
);
72
}
73
```
74
75
## Architecture
76
77
React Virtual is built around a single, powerful hook that manages virtualization state:
78
79
- **Measurement System**: Tracks item sizes using either fixed estimates or dynamic measurements
80
- **Viewport Calculation**: Determines which items are visible based on scroll position and container size
81
- **Overscan Management**: Renders additional items beyond the visible area for smooth scrolling
82
- **Imperative Scrolling**: Provides functions to programmatically scroll to specific items or offsets
83
- **Orientation Support**: Handles both vertical (default) and horizontal virtualization
84
85
## Capabilities
86
87
### useVirtual Hook
88
89
The main virtualization hook that manages the rendering of large lists, grids, and columns with optimal performance.
90
91
```javascript { .api }
92
/**
93
* Main virtualization hook for efficient rendering of large datasets
94
* @param options - Configuration object for virtualization behavior
95
* @returns Object containing virtual items and control functions
96
*/
97
function useVirtual(options: VirtualOptions): VirtualResult;
98
99
interface VirtualOptions {
100
/** Total number of items to virtualize (required) */
101
size: number;
102
/** Reference to the scrollable parent element (required) */
103
parentRef: React.RefObject<HTMLElement>;
104
/** Function to estimate size of each item (required, must be memoized with useCallback) */
105
estimateSize: (index: number) => number;
106
/** Number of items to render beyond visible area (default: 1) */
107
overscan?: number;
108
/** Enable horizontal virtualization using width/scrollLeft (default: false) */
109
horizontal?: boolean;
110
}
111
112
interface VirtualResult {
113
/** Array of currently visible virtual items */
114
items: VirtualItem[];
115
/** Total size of all virtualized content in pixels */
116
totalSize: number;
117
/** Function to scroll to a specific pixel offset */
118
scrollToOffset: (offset: number) => void;
119
/** Function to scroll to a specific item index */
120
scrollToIndex: (index: number) => void;
121
}
122
123
interface VirtualItem {
124
/** Zero-based index of the item */
125
index: number;
126
/** Starting position in pixels */
127
start: number;
128
/** Item size in pixels */
129
size: number;
130
/** Ending position in pixels */
131
end: number;
132
/** Ref callback for dynamic measurement */
133
measureRef: (element: HTMLElement | null) => void;
134
}
135
```
136
137
**Usage Patterns:**
138
139
**Row Virtualization (Vertical Lists):**
140
```javascript
141
const rowVirtualizer = useVirtual({
142
size: 10000,
143
parentRef: parentRef,
144
estimateSize: React.useCallback(() => 35, []),
145
overscan: 5,
146
});
147
```
148
149
**Column Virtualization (Horizontal Lists):**
150
```javascript
151
const columnVirtualizer = useVirtual({
152
horizontal: true,
153
size: 1000,
154
parentRef: parentRef,
155
estimateSize: React.useCallback(() => 100, []),
156
overscan: 5,
157
});
158
```
159
160
**Grid Virtualization (2D Virtualization):**
161
```javascript
162
// Use two separate hooks for rows and columns
163
const rowVirtualizer = useVirtual({
164
size: 10000,
165
parentRef: parentRef,
166
estimateSize: React.useCallback(() => 35, []),
167
overscan: 5,
168
});
169
170
const columnVirtualizer = useVirtual({
171
horizontal: true,
172
size: 10000,
173
parentRef: parentRef,
174
estimateSize: React.useCallback(() => 100, []),
175
overscan: 5,
176
});
177
178
// Render grid by mapping over both virtualizers
179
return (
180
<div ref={parentRef} style={{ height: "500px", width: "500px", overflow: "auto" }}>
181
<div
182
style={{
183
height: `${rowVirtualizer.totalSize}px`,
184
width: `${columnVirtualizer.totalSize}px`,
185
position: "relative",
186
}}
187
>
188
{rowVirtualizer.items.map((virtualRow) => (
189
<React.Fragment key={virtualRow.index}>
190
{columnVirtualizer.items.map((virtualColumn) => (
191
<div
192
key={virtualColumn.index}
193
style={{
194
position: "absolute",
195
top: 0,
196
left: 0,
197
width: `${virtualColumn.size}px`,
198
height: `${virtualRow.size}px`,
199
transform: `translateX(${virtualColumn.start}px) translateY(${virtualRow.start}px)`,
200
}}
201
>
202
Cell {virtualRow.index}, {virtualColumn.index}
203
</div>
204
))}
205
</React.Fragment>
206
))}
207
</div>
208
</div>
209
);
210
```
211
212
**Dynamic Measurement:**
213
```javascript
214
// For items with unknown sizes, use measureRef for runtime measurement
215
{rowVirtualizer.items.map((virtualRow) => (
216
<div
217
key={virtualRow.index}
218
ref={virtualRow.measureRef}
219
style={{
220
position: "absolute",
221
top: 0,
222
left: 0,
223
width: "100%",
224
transform: `translateY(${virtualRow.start}px)`,
225
}}
226
>
227
Content with dynamic height...
228
</div>
229
))}
230
```
231
232
**Imperative Scrolling:**
233
```javascript
234
// Scroll to specific item
235
const scrollToItem = (index) => {
236
rowVirtualizer.scrollToIndex(index);
237
};
238
239
// Scroll to specific offset
240
const scrollToTop = () => {
241
rowVirtualizer.scrollToOffset(0);
242
};
243
```
244
245
### Key Features
246
247
- **Performance Optimized**: Only renders visible items plus overscan, dramatically reducing DOM nodes
248
- **Flexible Sizing**: Supports fixed, variable, and dynamic item sizing
249
- **Multi-directional**: Handles vertical (default) and horizontal virtualization
250
- **Grid Support**: Combine row and column virtualizers for 2D grids
251
- **Smooth Scrolling**: Configurable overscan prevents visual gaps during fast scrolling
252
- **Imperative Control**: Programmatic scrolling to specific items or positions
253
- **Framework Agnostic**: Pure React hook with no additional dependencies beyond React
254
- **TypeScript Ready**: Full type definitions for enhanced development experience
255
256
### Error Handling
257
258
The hook expects:
259
- `estimateSize` to be memoized with `React.useCallback()` to prevent unnecessary re-calculations
260
- `parentRef` to reference an element with `overflow: auto` or `overflow: scroll`
261
- `size` to be a positive integer representing the total number of items
262
263
If these requirements aren't met, the virtualization may not work correctly or performance may be degraded.