MRT logoMaterial React Table

On This Page

    Async Loading Feature Guide

    While you are fetching your data, you may want to show some loading indicators. Material React Table has some nice loading UI features built in that look better than a simple spinner.

    This guide is mostly focused on the loading UI features. Make sure to also check out the Remote Data and React Query examples for server-side logic examples.

    Relevant Props

    1
    LinearProgressProps | ({ isTopToolbar, table }) => LinearProgressProps
    Material UI LinearProgress Props
    2
    SkeletonProps | ({ cell, column, row, table }) => SkeletonProps
    Material UI Skeleton Props

    Relevant State Options

    1
    boolean
    false
    2
    boolean
    false
    3
    boolean
    false

    isLoading UI

    Rather than coding your own spinner or loading indicator, you can simply set the isLoading state to true, and Material React Table will show progress bars and cell skeletons for you.

    <MaterialReactTable
    columns={columns}
    data={data ?? []} //fallback to array if data is undefined
    state={{ isLoading: true }}
    />

    Demo

    Open StackblitzOpen Code SandboxOpen on GitHub

    Rows per page

    1-10 of 10

    Source Code

    1import React, { useMemo } from 'react';
    2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
    3import { Person } from './makeData';
    4
    5const Example = () => {
    6 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    7 //column definitions...
    28 );
    29
    30 return (
    31 <MaterialReactTable
    32 columns={columns}
    33 data={[]}
    34 state={{ isLoading: true }}
    35 />
    36 );
    37};
    38
    39export default Example;
    40

    Only Show Progress Bars or Skeletons

    If you do not want both progress bars and cell skeletons to show, you can use the showProgressBars and showSkeletons states, instead.

    <MaterialReactTable
    columns={columns}
    data={data ?? []} //fallback to array if data is undefined
    state={{ showProgressBars: true }} //or showSkeletons
    />

    Customize Linear Progress Bars

    You can customize the linear progress bars by passing props to the muiLinearProgressProps prop.


    Demo

    DylanMurraydmurray@yopmail.comEast Daphne
    RaquelKohlerrkholer33@yopmail.comColumbus
    ErvinReingerereinger@mailinator.comSouth Linda
    BrittanyMcCulloughbmccullough44@mailinator.comLincoln
    BransonFramibframi@yopmain.comNew York
    KevinKleinkklien@mailinator.comNebraska

    Rows per page

    1-6 of 6

    Source Code

    1import React, { useEffect, useMemo, useState } from 'react';
    2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
    3import { data, type Person } from './makeData';
    4import { Button } from '@mui/material';
    5
    6const Example = () => {
    7 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    8 //column definitions...
    29 );
    30
    31 const [progress, setProgress] = useState(0);
    32
    33 //simulate random progress for demo purposes
    34 useEffect(() => {
    35 const interval = setInterval(() => {
    36 setProgress((oldProgress) => {
    37 const newProgress = Math.random() * 20;
    38 return Math.min(oldProgress + newProgress, 100);
    39 });
    40 }, 1000);
    41 return () => clearInterval(interval);
    42 }, []);
    43
    44 return (
    45 <MaterialReactTable
    46 columns={columns}
    47 data={data}
    48 muiLinearProgressProps={({ isTopToolbar }) => ({
    49 color: 'secondary',
    50 variant: 'determinate', //if you want to show exact progress value
    51 value: progress, //value between 0 and 100
    52 sx: {
    53 display: isTopToolbar ? 'block' : 'none', //hide bottom progress bar
    54 },
    55 })}
    56 renderTopToolbarCustomActions={() => (
    57 <Button onClick={() => setProgress(0)} variant="contained">
    58 Reset
    59 </Button>
    60 )}
    61 state={{ showProgressBars: true }}
    62 />
    63 );
    64};
    65
    66export default Example;
    67

    Full Loading and Server-Side Logic Example

    Here is a copy of the full React Query example.


    Demo

    Rows per page

    0-0 of 0

    Source Code

    1import React, { useMemo, useState } from 'react';
    2import {
    3 MaterialReactTable,
    4 type MRT_ColumnDef,
    5 type MRT_ColumnFiltersState,
    6 type MRT_PaginationState,
    7 type MRT_SortingState,
    8} from 'material-react-table';
    9import { IconButton, Tooltip } from '@mui/material';
    10import RefreshIcon from '@mui/icons-material/Refresh';
    11import {
    12 QueryClient,
    13 QueryClientProvider,
    14 useQuery,
    15} from '@tanstack/react-query';
    16
    17type UserApiResponse = {
    18 data: Array<User>;
    19 meta: {
    20 totalRowCount: number;
    21 };
    22};
    23
    24type User = {
    25 firstName: string;
    26 lastName: string;
    27 address: string;
    28 state: string;
    29 phoneNumber: string;
    30};
    31
    32const Example = () => {
    33 const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
    34 [],
    35 );
    36 const [globalFilter, setGlobalFilter] = useState('');
    37 const [sorting, setSorting] = useState<MRT_SortingState>([]);
    38 const [pagination, setPagination] = useState<MRT_PaginationState>({
    39 pageIndex: 0,
    40 pageSize: 10,
    41 });
    42
    43 const { data, isError, isFetching, isLoading, refetch } =
    44 useQuery<UserApiResponse>({
    45 queryKey: [
    46 'table-data',
    47 columnFilters, //refetch when columnFilters changes
    48 globalFilter, //refetch when globalFilter changes
    49 pagination.pageIndex, //refetch when pagination.pageIndex changes
    50 pagination.pageSize, //refetch when pagination.pageSize changes
    51 sorting, //refetch when sorting changes
    52 ],
    53 queryFn: async () => {
    54 const fetchURL = new URL(
    55 '/api/data',
    56 process.env.NODE_ENV === 'production'
    57 ? 'https://www.material-react-table.com'
    58 : 'http://localhost:3000',
    59 );
    60 fetchURL.searchParams.set(
    61 'start',
    62 `${pagination.pageIndex * pagination.pageSize}`,
    63 );
    64 fetchURL.searchParams.set('size', `${pagination.pageSize}`);
    65 fetchURL.searchParams.set(
    66 'filters',
    67 JSON.stringify(columnFilters ?? []),
    68 );
    69 fetchURL.searchParams.set('globalFilter', globalFilter ?? '');
    70 fetchURL.searchParams.set('sorting', JSON.stringify(sorting ?? []));
    71
    72 const response = await fetch(fetchURL.href);
    73 const json = (await response.json()) as UserApiResponse;
    74 return json;
    75 },
    76 keepPreviousData: true,
    77 });
    78
    79 const columns = useMemo<MRT_ColumnDef<User>[]>(
    80 () => [
    81 {
    82 accessorKey: 'firstName',
    83 header: 'First Name',
    84 },
    85 {
    86 accessorKey: 'lastName',
    87 header: 'Last Name',
    88 },
    89 {
    90 accessorKey: 'address',
    91 header: 'Address',
    92 },
    93 {
    94 accessorKey: 'state',
    95 header: 'State',
    96 },
    97 {
    98 accessorKey: 'phoneNumber',
    99 header: 'Phone Number',
    100 },
    101 ],
    102 [],
    103 );
    104
    105 return (
    106 <MaterialReactTable
    107 columns={columns}
    108 data={data?.data ?? []} //data is undefined on first render
    109 initialState={{ showColumnFilters: true }}
    110 manualFiltering
    111 manualPagination
    112 manualSorting
    113 muiToolbarAlertBannerProps={
    114 isError
    115 ? {
    116 color: 'error',
    117 children: 'Error loading data',
    118 }
    119 : undefined
    120 }
    121 onColumnFiltersChange={setColumnFilters}
    122 onGlobalFilterChange={setGlobalFilter}
    123 onPaginationChange={setPagination}
    124 onSortingChange={setSorting}
    125 renderTopToolbarCustomActions={() => (
    126 <Tooltip arrow title="Refresh Data">
    127 <IconButton onClick={() => refetch()}>
    128 <RefreshIcon />
    129 </IconButton>
    130 </Tooltip>
    131 )}
    132 rowCount={data?.meta?.totalRowCount ?? 0}
    133 state={{
    134 columnFilters,
    135 globalFilter,
    136 isLoading,
    137 pagination,
    138 showAlertBanner: isError,
    139 showProgressBars: isFetching,
    140 sorting,
    141 }}
    142 />
    143 );
    144};
    145
    146const queryClient = new QueryClient();
    147
    148const ExampleWithReactQueryProvider = () => (
    149 <QueryClientProvider client={queryClient}>
    150 <Example />
    151 </QueryClientProvider>
    152);
    153
    154export default ExampleWithReactQueryProvider;
    155