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
# | Prop Name 2 | Type | Default Value | More Info Links | |
---|---|---|---|---|---|
1 |
| Material UI LinearProgress Props | |||
2 |
| Material UI Skeleton Props | |||
Relevant State Options
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.
<MaterialReactTablecolumns={columns}data={data ?? []} //fallback to array if data is undefinedstate={{ isLoading: true }}/>
First Name | Last Name | Email | City |
---|---|---|---|
1import React, { useMemo } from 'react';2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';3import { Person } from './makeData';45const Example = () => {6 const columns = useMemo<MRT_ColumnDef<Person>[]>(7 //column definitions...28 );2930 return (31 <MaterialReactTable32 columns={columns}33 data={[]}34 state={{ isLoading: true }}35 />36 );37};3839export 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.
<MaterialReactTablecolumns={columns}data={data ?? []} //fallback to array if data is undefinedstate={{ showProgressBars: true }} //or showSkeletons/>
Customize Linear Progress Bars
You can customize the linear progress bars by passing props to the muiLinearProgressProps
prop.
First Name | Last Name | Email | City |
---|---|---|---|
Dylan | Murray | dmurray@yopmail.com | East Daphne |
Raquel | Kohler | rkholer33@yopmail.com | Columbus |
Ervin | Reinger | ereinger@mailinator.com | South Linda |
Brittany | McCullough | bmccullough44@mailinator.com | Lincoln |
Branson | Frami | bframi@yopmain.com | New York |
Kevin | Klein | kklien@mailinator.com | Nebraska |
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';56const Example = () => {7 const columns = useMemo<MRT_ColumnDef<Person>[]>(8 //column definitions...29 );3031 const [progress, setProgress] = useState(0);3233 //simulate random progress for demo purposes34 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 }, []);4344 return (45 <MaterialReactTable46 columns={columns}47 data={data}48 muiLinearProgressProps={({ isTopToolbar }) => ({49 color: 'secondary',50 variant: 'determinate', //if you want to show exact progress value51 value: progress, //value between 0 and 10052 sx: {53 display: isTopToolbar ? 'block' : 'none', //hide bottom progress bar54 },55 })}56 renderTopToolbarCustomActions={() => (57 <Button onClick={() => setProgress(0)} variant="contained">58 Reset59 </Button>60 )}61 state={{ showProgressBars: true }}62 />63 );64};6566export default Example;67
Full Loading and Server-Side Logic Example
Here is a copy of the full React Query example.
First Name | Last Name | Address | State | Phone Number |
---|---|---|---|---|
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';1617type UserApiResponse = {18 data: Array<User>;19 meta: {20 totalRowCount: number;21 };22};2324type User = {25 firstName: string;26 lastName: string;27 address: string;28 state: string;29 phoneNumber: string;30};3132const 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 });4243 const { data, isError, isFetching, isLoading, refetch } =44 useQuery<UserApiResponse>({45 queryKey: [46 'table-data',47 columnFilters, //refetch when columnFilters changes48 globalFilter, //refetch when globalFilter changes49 pagination.pageIndex, //refetch when pagination.pageIndex changes50 pagination.pageSize, //refetch when pagination.pageSize changes51 sorting, //refetch when sorting changes52 ],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 ?? []));7172 const response = await fetch(fetchURL.href);73 const json = (await response.json()) as UserApiResponse;74 return json;75 },76 keepPreviousData: true,77 });7879 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 );104105 return (106 <MaterialReactTable107 columns={columns}108 data={data?.data ?? []} //data is undefined on first render109 initialState={{ showColumnFilters: true }}110 manualFiltering111 manualPagination112 manualSorting113 muiToolbarAlertBannerProps={114 isError115 ? {116 color: 'error',117 children: 'Error loading data',118 }119 : undefined120 }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};145146const queryClient = new QueryClient();147148const ExampleWithReactQueryProvider = () => (149 <QueryClientProvider client={queryClient}>150 <Example />151 </QueryClientProvider>152);153154export default ExampleWithReactQueryProvider;155