What is react-virtual?
The react-virtual package is a lightweight and performant library for rendering large lists and tabular data in React applications. It helps in efficiently managing and displaying large datasets by only rendering the visible items, thus improving performance and reducing memory usage.
What are react-virtual's main functionalities?
Virtualized List
This feature allows you to create a virtualized list where only the visible items are rendered. This improves performance when dealing with large datasets.
import { useVirtual } from 'react-virtual';
function VirtualizedList({ items }) {
const parentRef = React.useRef();
const rowVirtualizer = useVirtual({
size: items.length,
parentRef,
estimateSize: React.useCallback(() => 35, []),
});
return (
<div ref={parentRef} style={{ height: `400px`, overflow: 'auto' }}>
<div style={{ height: `${rowVirtualizer.totalSize}px`, width: '100%' }}>
{rowVirtualizer.virtualItems.map(virtualRow => (
<div
key={virtualRow.index}
ref={virtualRow.measureRef}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualRow.start}px)`
}}
>
{items[virtualRow.index]}
</div>
))}
</div>
</div>
);
}
Virtualized Grid
This feature allows you to create a virtualized grid where only the visible cells are rendered. This is useful for rendering large tables or grids efficiently.
import { useVirtual } from 'react-virtual';
function VirtualizedGrid({ columns, rows }) {
const parentRef = React.useRef();
const columnVirtualizer = useVirtual({
size: columns.length,
parentRef,
estimateSize: React.useCallback(() => 100, []),
horizontal: true,
});
const rowVirtualizer = useVirtual({
size: rows.length,
parentRef,
estimateSize: React.useCallback(() => 35, []),
});
return (
<div ref={parentRef} style={{ height: `400px`, width: `600px`, overflow: 'auto' }}>
<div
style={{
height: `${rowVirtualizer.totalSize}px`,
width: `${columnVirtualizer.totalSize}px`,
position: 'relative',
}}
>
{rowVirtualizer.virtualItems.map(virtualRow => (
<div
key={virtualRow.index}
ref={virtualRow.measureRef}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
transform: `translateY(${virtualRow.start}px)`
}}
>
{columnVirtualizer.virtualItems.map(virtualColumn => (
<div
key={virtualColumn.index}
ref={virtualColumn.measureRef}
style={{
position: 'absolute',
top: 0,
left: 0,
height: '100%',
transform: `translateX(${virtualColumn.start}px)`
}}
>
{rows[virtualRow.index][virtualColumn.index]}
</div>
))}
</div>
))}
</div>
</div>
);
}
Other packages similar to react-virtual
react-window
react-window is a library for rendering large lists and tabular data efficiently. It is similar to react-virtual in that it only renders the visible items, but it is more lightweight and has a simpler API. However, react-virtual offers more flexibility and customization options.
react-virtualized
react-virtualized is another popular library for rendering large lists and tabular data. It offers a wide range of features and components, including grids, lists, tables, and more. Compared to react-virtual, react-virtualized is more feature-rich but also more complex and heavier.

Hooks for virtualizing scrollable elements in React
Enjoy this library? Try them all! React Table, React Query, React Form,
React Charts
Quick Features
- Row, Column, and Grid virtualization
- One single headless hook
- Fixed, variable and dynamic measurement modes
- Imperative scrollTo control for offset, indices and alignment
- Custom scrolling function support (eg. smooth scroll)
-
Examples
This library is being built and maintained by me, @tannerlinsley and I am always in need of more support to keep projects like this afloat. If you would like to get premium support, add your logo or name on this README, or simply just contribute to my open source Sponsorship goal, visit my Github Sponsors page!






Documentation
Installation
$ npm i --save react-virtual
$ yarn add react-virtual
Why?
React Virtual's most distinguishing feature is that it's just one single custom hook instead of a set of components. In more trendy terms, this means that it is "headless", allowing you to control 100% all of the markup and styles, exactly how you want.
React Virtual supplies you with primitive utilities that allow you to build any range of virtualized experiences. One testament to this is that you can combine 2 instances of useVirtual
onto the same markup to achieve a virtualized grid, where with other utilites, you would need to use a dedicated Grid
-like component.
Sample
This is just a quick sample of what it looks like to use React Virtual. Please refer to the examples for more usage patterns.
function RowVirtualizerFixed() {
const parentRef = React.useRef()
const rowVirtualizer = useVirtual({
size: 10000,
parentRef,
estimateSize: React.useCallback(() => 35, []),
})
return (
<>
<div
ref={parentRef}
className="List"
style={{
height: `150px`,
width: `300px`,
overflow: 'auto',
}}
>
<div
className="ListInner"
style={{
height: `${rowVirtualizer.totalSize}px`,
width: '100%',
position: 'relative',
}}
>
{rowVirtualizer.virtualItems.map(virtualRow => (
<div
key={virtualRow.index}
className={virtualRow.index % 2 ? 'ListItemOdd' : 'ListItemEven'}
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${virtualRow.size}px`,
transform: `translateY(${virtualRow.start}px)`,
}}
>
Row {virtualRow.index}
</div>
))}
</div>
</div>
</>
)
}
API
useVirtual
const {
virtualItems: [
{ index, start, size, end, measureRef },
],
totalSize,
scrollToIndex,
scrollToOffset,
} = useVirtual({
size,
parentRef,
estimateSize,
overscan,
horizontal,
scrollToFn,
useObserver,
})
Options
size: Integer
- Required
- The total count of elements
parentRef: React.useRef(DOMElement)
- Required
- The parent element whose inner-content is scrollable
estimateSize: Function(index) => Integer
- Required
- Must be memoized using
React.useCallback()
- This function receives the index of each item and should return either:
- A fixed size
- A variable size per-item
- A best-guess size (when using dynamic measurement rendering)
- When this function's memoization changes, the entire list is recalculated
overscan: Integer
- Defaults to
1
- The amount of items to load both behind and ahead of the current window range
horizontal: Boolean
- Defaults to
false
- When
true
, this virtualizer will use width
and scrollLeft
instead of height
and scrollTop
to determine size and offset of virtualized items.
scrollToFn: Function(offset, defaultScrollToFn) => void 0
- Optional
- This function, if passed, is responsible for implementing the scrollTo logic for the parentRef which is used when methods like
scrollToOffset
and scrollToIndex
are called. - Eg. You can use this function to implement smooth scrolling by using the supplied offset and the
defaultScrollToFn
as seen in the sandbox's Smooth Scroll example.
useObserver: Function(parentRef) => ({ width: number; height: number })
- Optional
- This hook, if passed, is responsible for getting
parentRef
's dimensions - Eg. You can use this hook to replace @reach/observe-rect that
react-virtual
uses by default with ResizeObserver API
paddingStart: Integer
- Defaults to
0
- The amount of padding in pixels to add to the start of the virtual list
paddingEnd: Integer
- Defaults to
0
- The amount of padding in pixels to add to the end of the virtual list
onScrollElement: React.useRef(DOMElement)
- Optional
- Allows using a different element to bind the
onScroll
event to
scrollOffsetFn: Function(event?: Event) => number
- Optional
- This function, if passed, is called on scroll to get the scroll offest rather than using
parentRef
's width
or height
keyExtractor: Function(index) => String | Integer
- Optional
- This function receives the index of each item and should return the item's unique ID.
- This function should be passed whenever dynamic measurement rendering is enabled and the size or order of items in the list changes.
Returns
virtualItems: Array<item>
item: Object
index: Integer
start: Integer
- The starting measurement of the item
- Most commonly used for positioning elements
size: Integer
- The static/variable or, if dynamically rendered, the measured size of the item
end: Integer
- The ending measurement of the item
measureRef: React.useRef | Function(el: DOMElement) => void 0
- The ref/function to place on the rendered element to enable dynamic measurement rendering
totalSize: Integer
- The total size of the entire virtualizer
- When using dynamic measurement refs, this number may change as items are measured after they are rendered.
scrollToIndex: Function(index: Integer, { align: String }) => void 0
- Call this function to scroll the top/left of the parentRef element to the start of the item located at the passed index.
align: 'start' | 'center' | 'end' | 'auto'
- Defaults to
auto
start
places the item at the top/left of the visible scroll areacenter
places the item in the center of the visible scroll areaend
places the item at the bottom/right of the visible scroll areaauto
brings the item into the visible scroll area either at the start or end, depending on which is closer. If the item is already in view, it is placed at the top/left
of the visible scroll area.
scrollToOffset: Function(offsetInPixels: Integer, { align: String }) => void 0
- Call this function to scroll the top/left of the parentRef element to the passed pixel offset.
align: 'start' | 'center' | 'end' | 'auto'
- Defaults to
start
start
places the offset at the top/left of the visible scroll areacenter
places the offset in the center of the visible scroll areaend
places the offset at the bottom/right of the visible scroll areaauto
brings the offset into the visible scroll area either at the start or end, depending on which is closer. If the offset is already in view, it is placed at the top/left
of the visible scroll area.
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!