MRT logoMaterial React Table

Sorting Feature Guide

Material React Table supports almost any sorting scenario you may have. Client-side sorting is enabled by default, but you can opt to implement your own server-side sorting logic or even replace the default client-side sorting with your own implementation.

Relevant Table Options

1
boolean
true
MRT Global Filtering Docs
2
boolean
3
boolean
true
4
boolean
true
5
(table: Table<TData>) => () => RowModel<TData>
TanStack Table Sorting Docs
6
(e: unknown) => boolean
TanStack Table Sorting Docs
7
boolean
TanStack Table Sorting Docs
8
number
TanStack Table Sorting Docs
9
OnChangeFn<SortingState>
TanStack Table Sorting Docs
10
boolean
TanStack Table Sorting Docs
11
Record<string, SortingFn>
TanStack Table Sorting Docs

Relevant Column Options

1
boolean
true
2
boolean
3
boolean
false
4
boolean
5
false | 1 | -1
6
SortingFnOption

Relevant State Options

1
Array<{ id: string, desc: boolean }>
[]
TanStack Table Sorting Docs

Disable Sorting

Sorting can be disabled globally by setting the enableSorting table option to false. This will disable sorting for all columns. You can also disable sorting for individual columns by setting the enableSorting column option to false.

const columns = [
{
accessorKey: 'name',
header: 'Name',
enableSorting: false, // disable sorting for this column
},
];
const table = useMaterialReactTable({
columns,
data,
enableSorting: false, //disable sorting for all columns
});

Initial/Default Sorting

You can sort by a column or multiple columns by default by setting the sorting state option in either the initialState or state props.

const table = useMaterialReactTable({
columns,
data,
initialState: {
sorting: [
{
id: 'age', //sort by age by default on page load
desc: true,
},
{
id: 'lastName', //then sort by lastName if age is the same
desc: true,
},
],
},
});

Default Sorting Features

Client-side sorting is enabled by default. When sorting is toggled on for a column, the table will be sorted by an alphanumeric sorting algorithm by default.

Multi-Sorting

Multi-sorting is also enabled by default, which means you can sort by multiple columns at once. You can do this by clicking on a column header while holding down the shift key. The table will then be sorted by the previously sorted column, followed by the newly clicked column. Alternatively, if you want multi-sorting to be the default click behavior without the need to hold shift, you can set the isMultiSortEvent table option to () => true.

const table = useMaterialReactTable({
columns,
data,
isMultiSortEvent: () => true, //multi-sorting will be the default click behavior without the need to hold shift
});

You can limit the number of columns that can be sorted at once by setting the maxMultiSortColCount prop, or you can disable multi-sorting entirely by setting the enableMultiSort table option to false.

Sorting Removal

By default, users can remove a sort on a column by clicking through the sort direction options or selecting "Clear Sort" from the column actions menu. You can disable this feature by setting the enableSortingRemoval table option to false.

const table = useMaterialReactTable({
columns,
data,
enableSortingRemoval: false, //users will not be able to remove a sort on a column
});

Sort Direction

By default, columns with string datatypes will sort alphabetically in ascending order, but columns with number datatypes will sort numerically in descending order. You can change the default sort direction per column by specifying the sortDescFirst column option to either true or false. You can also change the default sort direction globally by setting the sortDescFirst table option to either true or false.

VioletDoeSan FranciscoCalifornia100000
MasonZhangSacramentoCalifornia100000
LebronJamesIndianapolisIndiana40000
JosephWilliamsValentineNebraska100000
AllisonBrownOmahaNebraska10000
HarrySmithHickmanNebraska20000
SallyWilliamsonAllianceNebraska30000
NoahBrownToledoOhio50000
MichaelMcGinnisHarrisonburgVirginia150000
1-9 of 9

Source Code

1import {
2 MaterialReactTable,
3 useMaterialReactTable,
4 type MRT_ColumnDef,
5} from 'material-react-table';
6import { data, type Person } from './makeData';
7import { Button } from '@mui/material';
8
9const columns: MRT_ColumnDef<Person>[] = [
10 {
11 accessorKey: 'firstName',
12 header: 'First Name',
13 sortDescFirst: false, //sort first name in ascending order by default on first sort click (default for non-numeric columns)
14 },
15 //column definitions...
29 {
30 accessorKey: 'salary',
31 header: 'Salary',
32 sortDescFirst: true, //sort salary in descending order by default on first sort click (default for numeric columns)
33 },
34];
35
36const Example = () => {
37 const table = useMaterialReactTable({
38 columns,
39 data,
40 isMultiSortEvent: () => true, //now no need to hold `shift` key to multi-sort
41 maxMultiSortColCount: 3, //prevent more than 3 columns from being sorted at once
42 initialState: {
43 sorting: [
44 { id: 'state', desc: false }, //sort by state in ascending order by default
45 { id: 'city', desc: true }, //then sort by city in descending order by default
46 ],
47 },
48 renderTopToolbarCustomActions: ({ table }) => (
49 <Button onClick={() => table.resetSorting(true)}>
50 Clear All Sorting
51 </Button>
52 ),
53 });
54
55 return <MaterialReactTable table={table} />;
56};
57
58export default Example;
59

Sorting Functions

By default, Material React Table will use an alphanumeric sorting function for all columns.

There are six built-in sorting functions you can choose from: alphanumeric, alphanumericCaseSensitive, text, textCaseSensitive, datetime, and basic. You can learn more about these built-in sorting functions in the TanStack Table Sorting API docs.

Add Custom Sorting Functions

If none of these sorting functions meet your needs, you can add your own custom sorting functions by specifying more sorting functions in the sortingFns table option.

const table = useMaterialReactTable({
columns,
data,
sortingFns: {
//will add a new sorting function to the list of other sorting functions already available
myCustomSortingFn: (rowA, rowB, columnId) => // your custom sorting logic
},
})

Change Sorting Function Per Column

You can now choose a sorting function for each column by either passing a string value of the built-in sorting function names to the sortingFn column option or by passing a custom sorting function to the sortingFn column option.

const columns = [
{
accessorKey: 'name',
header: 'Name',
sortingFn: 'textCaseSensitive', //use the built-in textCaseSensitive sorting function instead of the default alphanumeric sorting function
},
{
accessorKey: 'age',
header: 'Age',
//use your own custom sorting function instead of any of the built-in sorting functions
sortingFn: (rowA, rowB, columnId) => // your custom sorting logic
},
];

Manual Server-Side Sorting

If you are working with large data sets, you may want to let your back-end APIs handle all of the sorting and pagination processing instead of doing it client-side. You can do this by setting the manualSorting table option to true. This will disable the default client-side sorting and pagination features and will let you implement your own sorting and pagination logic.

When manualSorting is set to true, Material React Table assumes that your data is already sorted by the time you are passing it to the table.

If you need to sort your data in a back-end API, then you will also probably need access to the internal sorting state from the table. You can do this by managing the sorting state yourself and then passing it to the table via the state table option. You can also pass a callback function to the onSortingChange prop, which will be called whenever the sorting state changes internally in the table

const [sorting, setSorting] = useState([]);
const table = useMaterialReactTable({
columns,
data,
manualSorting: true,
state: { sorting },
onSortingChange: setSorting,
});
useEffect(() => {
//do something with the sorting state when it changes
//or use table.getState().sorting
}, [sorting]);
return <MaterialReactTable table={table} />;

Remote Sorting Example

Here is the full Remote Data example showing how to implement server-side sorting, filtering, and pagination with Material React Table.

0-0 of 0

Source Code

1import { useEffect, useMemo, useState } from 'react';
2import {
3 MaterialReactTable,
4 useMaterialReactTable,
5 type MRT_ColumnDef,
6 type MRT_ColumnFiltersState,
7 type MRT_PaginationState,
8 type MRT_SortingState,
9} from 'material-react-table';
10
11type UserApiResponse = {
12 data: Array<User>;
13 meta: {
14 totalRowCount: number;
15 };
16};
17
18type User = {
19 firstName: string;
20 lastName: string;
21 address: string;
22 state: string;
23 phoneNumber: string;
24};
25
26const Example = () => {
27 //data and fetching state
28 const [data, setData] = useState<User[]>([]);
29 const [isError, setIsError] = useState(false);
30 const [isLoading, setIsLoading] = useState(false);
31 const [isRefetching, setIsRefetching] = useState(false);
32 const [rowCount, setRowCount] = useState(0);
33
34 //table state
35 const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>(
36 [],
37 );
38 const [globalFilter, setGlobalFilter] = useState('');
39 const [sorting, setSorting] = useState<MRT_SortingState>([]);
40 const [pagination, setPagination] = useState<MRT_PaginationState>({
41 pageIndex: 0,
42 pageSize: 10,
43 });
44
45 //if you want to avoid useEffect, look at the React Query example instead
46 useEffect(() => {
47 const fetchData = async () => {
48 if (!data.length) {
49 setIsLoading(true);
50 } else {
51 setIsRefetching(true);
52 }
53
54 const url = new URL(
55 '/api/data',
56 process.env.NODE_ENV === 'production'
57 ? 'https://www.material-react-table.com'
58 : 'http://localhost:3000',
59 );
60 url.searchParams.set(
61 'start',
62 `${pagination.pageIndex * pagination.pageSize}`,
63 );
64 url.searchParams.set('size', `${pagination.pageSize}`);
65 url.searchParams.set('filters', JSON.stringify(columnFilters ?? []));
66 url.searchParams.set('globalFilter', globalFilter ?? '');
67 url.searchParams.set('sorting', JSON.stringify(sorting ?? []));
68
69 try {
70 const response = await fetch(url.href);
71 const json = (await response.json()) as UserApiResponse;
72 setData(json.data);
73 setRowCount(json.meta.totalRowCount);
74 } catch (error) {
75 setIsError(true);
76 console.error(error);
77 return;
78 }
79 setIsError(false);
80 setIsLoading(false);
81 setIsRefetching(false);
82 };
83 fetchData();
84 // eslint-disable-next-line react-hooks/exhaustive-deps
85 }, [
86 columnFilters, //re-fetch when column filters change
87 globalFilter, //re-fetch when global filter changes
88 pagination.pageIndex, //re-fetch when page index changes
89 pagination.pageSize, //re-fetch when page size changes
90 sorting, //re-fetch when sorting changes
91 ]);
92
93 const columns = useMemo<MRT_ColumnDef<User>[]>(
94 () => [
95 {
96 accessorKey: 'firstName',
97 header: 'First Name',
98 },
99 //column definitions...
117 ],
118 [],
119 );
120
121 const table = useMaterialReactTable({
122 columns,
123 data,
124 enableRowSelection: true,
125 getRowId: (row) => row.phoneNumber,
126 initialState: { showColumnFilters: true },
127 manualFiltering: true,
128 manualPagination: true,
129 manualSorting: true,
130 muiToolbarAlertBannerProps: isError
131 ? {
132 color: 'error',
133 children: 'Error loading data',
134 }
135 : undefined,
136 onColumnFiltersChange: setColumnFilters,
137 onGlobalFilterChange: setGlobalFilter,
138 onPaginationChange: setPagination,
139 onSortingChange: setSorting,
140 rowCount,
141 state: {
142 columnFilters,
143 globalFilter,
144 isLoading,
145 pagination,
146 showAlertBanner: isError,
147 showProgressBars: isRefetching,
148 sorting,
149 },
150 });
151
152 return <MaterialReactTable table={table} />;
153};
154
155export default Example;
156

View Extra Storybook Examples