MRT logoMaterial React Table

    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

    1
    boolean
    2
    MutableRefObject<Virtualizer | null>
    3
    Partial<VirtualizerOptions<HTMLDivElement>>

    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.

    <MaterialReactTable
    columns={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.

    <MaterialReactTable
    columns={columns}
    data={data}
    enablePagination={false}
    enableRowVirtualization
    virtualizerProps={{
    overscan: 25, //adjust the number or rows that are rendered above and below the visible area of the table
    estimateHeight: () => 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 changes
    virtualizerInstanceRef.current.scrollToIndex(0);
    }
    }, [sorting]);
    return (
    <MaterialReactTable
    columns={columns}
    data={data}
    enableRowVirtualization
    virtualizerInstanceRef={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.


    Demo

    Open Code SandboxOpen on GitHub

    Source Code

    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';
    8
    9const Example: FC = () => {
    10 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    11 //column definitions...
    68 );
    69
    70 //optionally access the underlying virtualizer instance
    71 const virtualizerInstanceRef = useRef<Virtualizer>(null);
    72
    73 const [data, setData] = useState<Person[]>([]);
    74 const [isLoading, setIsLoading] = useState(true);
    75 const [sorting, setSorting] = useState<SortingState>([]);
    76
    77 useEffect(() => {
    78 if (typeof window !== 'undefined') {
    79 setData(makeData(10_000));
    80 setIsLoading(false);
    81 }
    82 }, []);
    83
    84 useEffect(() => {
    85 if (virtualizerInstanceRef.current) {
    86 //scroll to the top of the table when the sorting changes
    87 virtualizerInstanceRef.current.scrollToIndex(0);
    88 }
    89 }, [sorting]);
    90
    91 return (
    92 <MaterialReactTable
    93 columns={columns}
    94 data={data} //10,000 rows
    95 enableBottomToolbar={false}
    96 enableGlobalFilterModes
    97 enablePagination={false}
    98 enableRowNumbers
    99 enableRowVirtualization
    100 initialState={{ density: 'compact' }}
    101 muiTableContainerProps={{ sx: { maxHeight: '600px' } }}
    102 onSortingChange={setSorting}
    103 state={{ isLoading, sorting }}
    104 virtualizerInstanceRef={virtualizerInstanceRef} //optional
    105 virtualizerProps={{ overscan: 20 }} //optionally customize the virtualizer
    106 />
    107 );
    108};
    109
    110export default Example;
    111

    View Extra Storybook Examples