Row Virtualization Feature Guide
Virtualization is useful when you have a lot of data you want to display client-side all at once, without having to use pagination. Material React Table makes this as simple as possible, thanks to @tanstack/react-virtual
.
NOTE: You should only enable row virtualization if you have a large number of rows. Depending on the size of the table, if you are rendering less than a couple dozen rows at a time, you will actually just be adding extra overhead to the table renders. Virtualization only becomes necessary when you have over 100 rows or so at the same time with no pagination.
Relevant Props
What is Virtualization?
Virtualization, or virtual scrolling, works by only rendering the rows that are visible on the screen. This is useful for performance and user experience, as we can make it appear that there are hundreds, thousands, or tens of thousands of rows in the table all at once, but in reality, the table will only render the couple dozen rows that are visible on the screen.
For more reading on the concept of virtualization, we recommend this blog post by LogRocket.
Does Your Table Even Need Virtualization?
If your table is already paginated, you probably don't need virtualization. If your table is not rendering more than 100 rows at a time, you might not really need virtualization.
There is a tiny bit of extra overhead that gets added to your table's rendering when virtualization is enabled, so don't just enable it for every table. That being said, if your table does have well over 100 rows that it is trying to render all at once without pagination, performance will be night and day once it is enabled.
If your table is not rendering more than 100 rows at a time, you might not need virtualization enabled!
Enable Row Virtualization
Enabling row virtualization is as simple as setting the enableRowVirtualization
prop to true
. However, you will probably also want to turn off pagination, which you can do by setting enablePagination
to false
.
<MaterialReactTablecolumns={columns}data={data}enablePagination={false}enableRowVirtualization/>
WARNING: Don't enable row virtualization conditionally. It may break React's Rule of Hooks, and/or cause other UI jumpiness.
Row Virtualization Side Effects
When Row Virtualization is enabled, a CSS table-layout: fixed
style is automatically added to the <table>
element to prevent columns wiggling back and forth during scrolling due to body cells having variating widths.
This means that you may want to manually specify the width of all of your columns in the column definitions with the size
option, since the browser will no longer automatically make columns wider as needed.
For further reading on how table-layout fixed
vs auto
works, we recommend this blog post by CSS-Tricks.
When Row Virtualization is enabled, a CSS
table-layout: fixed
style is automatically added to the<table>
element
Customize Virtualizer Props
You can adjust some of the virtualizer props that are used internally. The most useful ones are the overscan
and estimateHeight
options. You may want to adjust these values if you have unusual row heights that is causing the default scrolling to act weirdly.
<MaterialReactTablecolumns={columns}data={data}enablePagination={false}enableRowVirtualizationvirtualizerProps={{overscan: 25, //adjust the number or rows that are rendered above and below the visible area of the tableestimateHeight: () => 200, //if your rows are about 200px tall, could try this}}/>
See the official TanStack Virtualizer Options API Docs for more information.
Access Underlying Virtualizer Instance
In a similar way that you can access the underlying table instance, you can also access the underlying virtualizer instance. This can be useful for accessing methods like the scrollToIndex
method, which can be used to programmatically scroll to a specific row.
const virtualizerInstanceRef = useRef<Virtualizer>(null);useEffect(() => {if (virtualizerInstanceRef.current) {//scroll to the top of the table when sorting changesvirtualizerInstanceRef.current.scrollToIndex(0);}}, [sorting]);return (<MaterialReactTablecolumns={columns}data={data}enableRowVirtualizationvirtualizerInstanceRef={virtualizerInstanceRef}/>);
See the official TanStack Virtualizer Instance API Docs for more information.
Full Row Virtualization Example
Try out the performance of the table below with 10,000 rows! Filtering, Search, and Sorting also maintain usable performance.
# | First Name | Middle Name | Last Name | Email Address | Phone Number | Address | Zip Code | City | State | Country | Pet Name | Age |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1import React, { FC, useEffect, useMemo, useRef, useState } from 'react';2import MaterialReactTable, {3 MRT_ColumnDef,4 Virtualizer,5} from 'material-react-table';6import { SortingState } from '@tanstack/react-table';7import { makeData, Person } from './makeData';89const Example: FC = () => {10 const columns = useMemo<MRT_ColumnDef<Person>[]>(11 //column definitions...68 );6970 //optionally access the underlying virtualizer instance71 const virtualizerInstanceRef = useRef<Virtualizer>(null);7273 const [data, setData] = useState<Person[]>([]);74 const [isLoading, setIsLoading] = useState(true);75 const [sorting, setSorting] = useState<SortingState>([]);7677 useEffect(() => {78 if (typeof window !== 'undefined') {79 setData(makeData(10_000));80 setIsLoading(false);81 }82 }, []);8384 useEffect(() => {85 if (virtualizerInstanceRef.current) {86 //scroll to the top of the table when the sorting changes87 virtualizerInstanceRef.current.scrollToIndex(0);88 }89 }, [sorting]);9091 return (92 <MaterialReactTable93 columns={columns}94 data={data} //10,000 rows95 enableBottomToolbar={false}96 enableGlobalFilterModes97 enablePagination={false}98 enableRowNumbers99 enableRowVirtualization100 initialState={{ density: 'compact' }}101 muiTableContainerProps={{ sx: { maxHeight: '600px' } }}102 onSortingChange={setSorting}103 state={{ isLoading, sorting }}104 virtualizerInstanceRef={virtualizerInstanceRef} //optional105 virtualizerProps={{ overscan: 20 }} //optionally customize the virtualizer106 />107 );108};109110export default Example;111