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 StackblitzOpen Code SandboxOpen on GitHub

    Source Code

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

    View Extra Storybook Examples