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
# | Prop Name | Type | Default Value | More Info Links | |
---|---|---|---|---|---|
1 |
|
| MRT Global Filtering Docs | ||
2 |
| ||||
3 |
|
| |||
4 |
|
| |||
5 |
| TanStack Table Sorting Docs | |||
6 |
| TanStack Table Sorting Docs | |||
7 |
| TanStack Table Sorting Docs | |||
8 |
| TanStack Table Sorting Docs | |||
9 |
| TanStack Table Sorting Docs | |||
10 |
| TanStack Table Sorting Docs | |||
11 |
| TanStack Table Sorting Docs | |||
Relevant Column Options
Relevant State Options
# | State Option | Type | Default Value | More Info Links | |
---|---|---|---|---|---|
1 |
|
| 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 loaddesc: true,},{id: 'lastName', //then sort by lastName if age is the samedesc: 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 the basic
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
.
First Name | Last Name | City 2 | State 1 | Salary |
---|---|---|---|---|
Violet | Doe | San Francisco | California | 100000 |
Mason | Zhang | Sacramento | California | 100000 |
Lebron | James | Indianapolis | Indiana | 40000 |
Joseph | Williams | Valentine | Nebraska | 100000 |
Allison | Brown | Omaha | Nebraska | 10000 |
Harry | Smith | Hickman | Nebraska | 20000 |
Sally | Williamson | Alliance | Nebraska | 30000 |
Noah | Brown | Toledo | Ohio | 50000 |
Michael | McGinnis | Harrisonburg | Virginia | 150000 |
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';89const 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];3536const Example = () => {37 const table = useMaterialReactTable({38 columns,39 data,40 isMultiSortEvent: () => true, //now no need to hold `shift` key to multi-sort41 maxMultiSortColCount: 3, //prevent more than 3 columns from being sorted at once42 initialState: {43 sorting: [44 { id: 'state', desc: false }, //sort by state in ascending order by default45 { id: 'city', desc: true }, //then sort by city in descending order by default46 ],47 },48 renderTopToolbarCustomActions: ({ table }) => (49 <Button onClick={() => table.resetSorting(true)}>50 Clear All Sorting51 </Button>52 ),53 });5455 return <MaterialReactTable table={table} />;56};5758export default Example;59
Sorting Functions
By default, Material React Table will use the basic
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 availablemyCustomSortingFn: (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 basic sorting function},{accessorKey: 'age',header: 'Age',//use your own custom sorting function instead of any of the built-in sorting functionssortingFn: (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 totrue
, Material React Table assumes that yourdata
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.
First Name | Last Name | Address | State | Phone Number | |
---|---|---|---|---|---|
No records to display |
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';1011type UserApiResponse = {12 data: Array<User>;13 meta: {14 totalRowCount: number;15 };16};1718type User = {19 firstName: string;20 lastName: string;21 address: string;22 state: string;23 phoneNumber: string;24};2526const Example = () => {27 //data and fetching state28 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);3334 //table state35 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 });4445 //if you want to avoid useEffect, look at the React Query example instead46 useEffect(() => {47 const fetchData = async () => {48 if (!data.length) {49 setIsLoading(true);50 } else {51 setIsRefetching(true);52 }5354 const url = new URL('/api/data', location.origin);55 url.searchParams.set(56 'start',57 `${pagination.pageIndex * pagination.pageSize}`,58 );59 url.searchParams.set('size', `${pagination.pageSize}`);60 url.searchParams.set('filters', JSON.stringify(columnFilters ?? []));61 url.searchParams.set('globalFilter', globalFilter ?? '');62 url.searchParams.set('sorting', JSON.stringify(sorting ?? []));6364 try {65 const response = await fetch(url.href);66 const json = (await response.json()) as UserApiResponse;67 setData(json.data);68 setRowCount(json.meta.totalRowCount);69 } catch (error) {70 setIsError(true);71 console.error(error);72 return;73 }74 setIsError(false);75 setIsLoading(false);76 setIsRefetching(false);77 };78 fetchData();79 // eslint-disable-next-line react-hooks/exhaustive-deps80 }, [81 columnFilters, //re-fetch when column filters change82 globalFilter, //re-fetch when global filter changes83 pagination.pageIndex, //re-fetch when page index changes84 pagination.pageSize, //re-fetch when page size changes85 sorting, //re-fetch when sorting changes86 ]);8788 const columns = useMemo<MRT_ColumnDef<User>[]>(89 () => [90 {91 accessorKey: 'firstName',92 header: 'First Name',93 },94 //column definitions...112 ],113 [],114 );115116 const table = useMaterialReactTable({117 columns,118 data,119 enableRowSelection: true,120 getRowId: (row) => row.phoneNumber,121 initialState: { showColumnFilters: true },122 manualFiltering: true,123 manualPagination: true,124 manualSorting: true,125 muiToolbarAlertBannerProps: isError126 ? {127 color: 'error',128 children: 'Error loading data',129 }130 : undefined,131 onColumnFiltersChange: setColumnFilters,132 onGlobalFilterChange: setGlobalFilter,133 onPaginationChange: setPagination,134 onSortingChange: setSorting,135 rowCount,136 state: {137 columnFilters,138 globalFilter,139 isLoading,140 pagination,141 showAlertBanner: isError,142 showProgressBars: isRefetching,143 sorting,144 },145 });146147 return <MaterialReactTable table={table} />;148};149150export default Example;151
View Extra Storybook Examples