MRT logoMaterial React Table

Column Filtering Feature Guide

Filtering is one of the most powerful features of Material React Table and is enabled by default. There is a lot of flexibility and customization available here. Whether you want to customize the powerful client-side filtering already built in or implement your own server-side filtering, Material React Table has got you covered.

Relevant Props

1
Array<MRT_FilterOption | string> | null
MRT Column Filtering Docs
2
boolean
false
MRT Column Filtering Docs
3
boolean
true
MRT Column Filtering Docs
4
boolean
true
TanStack Filters Docs
5
boolean
true
MRT Column Filtering Docs
6
boolean
true
TanStack Filters Docs
7
Record<string, FilterFn>
TanStack Table Filters Docs
8
boolean
false
TanStack Filtering Docs
9
() => Map<any, number>
TanStack Table Filters Docs
10
() => RowModel<TData>
TanStack Table Filters Docs
11
() => Map<any, number>
TanStack Table Filters Docs
12
() => RowModel<TData>
TanStack Table Filters Docs
13
boolean
TanStack Table Filters Docs
14
number
100
TanStack Table Filtering Docs
15
CheckboxProps | ({ column, table}) => CheckboxProps
Material UI Checkbox Props
16
SliderProps | ({ column, table}) => SliderProps
Material UI Slider Props
17
TextFieldProps | ({ table, column, rangeFilterIndex}) => TextFieldProps
Material UI TextField Props
18
OnChangeFn<{ [key: string]: MRT_FilterOption }>
19
OnChangeFn<ColumnFiltersState>
TanStack Table Filter Docs
20
OnChangeFn<boolean>
21
({ column, internalFilterOptions, onSelectFilterMode, table }) => ReactNode[]

Relevant Column Options

1
Array<string>
2
boolean
MRT Column Filtering Docs
3
boolean
MRT Column Filtering Docs
4
boolean
MRT Column Filtering Docs
5
({ column, header, table }) => ReactNode
MRT Column Filtering Docs
6
MRT_FilterFn
'fuzzy'
7
Array<string | { text: string; value: string }>
8
'text' | 'select' | 'multi-select' | 'range' | 'range-slider' | 'checkbox'
'text'
9
Checkbox | ({ column, table }) => CheckboxProps
Material UI Checkbox Props
10
SliderProps | ({ column, table}) => SliderProps
Material UI Slider Props
11
TextFieldProps | ({ column, rangeFilterIndex, table }) => TextFieldProps
Material UI TextField Props
12

Relevant State Options

1
{ [key: string]: MRT_FilterFn }
2
Array<{id: string, value: unknown}>
{}
TanStack Table Filters Docs
3
boolean
false

Disable Filtering Features

Various subsets of filtering features can be disabled. If you want to disable filtering completely, you can set the enableColumnFilters prop to false to remove all filters from each column. Alternatively, enableColumnFilter can be set to false for individual columns.

enableFilters can be set to false to disable both column filters and the global search filter.


1HughJayMungus
2LeroyLeroyJenkins

1-2 of 2

Source Code

1import React, { useMemo } from 'react';
2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
3
4const Example = () => {
5 const columns = useMemo(
6 () =>
7 [
8 {
9 accessorKey: 'id',
10 enableColumnFilter: false, // could disable just this column's filter
11 header: 'ID',
12 },
13 //column definitions...
27 ] as MRT_ColumnDef<(typeof data)[0]>[],
28 [],
29 );
30
31 const data = useMemo(
32 //data definitions...
49 );
50
51 return (
52 <MaterialReactTable
53 columns={columns}
54 data={data}
55 enableColumnFilters={false} //disable all column filters
56 />
57 );
58};
59
60export default Example;
61

Filter Match Highlighting

New in v1.6

Filter Match Highlighting is a new featured enabled by default that will highlight text in the table body cells that matches the current filter query with a shade of the theme.palette.warning.main color.

Filter Match Highlighting will only work on columns with the default text filter variant. Also, if you are using a custom Cell render override for a column, you will need to use the renderedCellValue prop instead of cell.getValue() in order to preserve the filter match highlighting.

const columns = [
{
accessorKey: 'name',
header: 'Name',
Cell: ({ renderedCellValue }) => <span>{renderedCellValue}</span>, // use renderedCellValue instead of cell.getValue()
},
];

Disable Filter Match Highlighting

This feature can be disabled by setting the enableFilterMatchHighlighting prop to false.

<MaterialReactTable
columns={columns}
data={data}
enableFilterMatchHighlighting={false}
/>

Filter Variants

Material React Table has several built-in filter variants for advanced filtering. These can be specified on a per-column basis using the filterVariant option. The following variants are available:

  • 'text' - shows the default text field

  • 'select' - shows a select dropdown with the options from faceted values or specified in filterSelectOptions

  • 'multi-select' - shows a select dropdown with the options from faceted values or specified in filterSelectOptions and allows multiple selections with checkboxes

  • 'range' - shows min and max text fields for filtering a range of values

  • 'range-slider' - shows a slider for filtering a range of values

  • 'checkbox' - shows a checkbox for filtering by 'true' or 'false' values (Strings)


ActiveTanner Linsley42$100,000.00San FranciscoCalifornia
ActiveKevin Vandy51$80,000.00RichmondVirginia
InactiveJohn Doe27$120,000.00RiversideSouth Carolina
ActiveJane Doe32$150,000.00San FranciscoCalifornia
InactiveJohn Smith42$75,000.00Los AngelesCalifornia
ActiveJane Smith51$56,000.00BlacksburgVirginia
InactiveSamuel Jackson27$90,000.00New YorkNew York

1-7 of 7

Source Code

1import React, { useMemo } from 'react';
2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
3import { citiesList, data, Person, usStateList } from './makeData';
4
5const Example = () => {
6 const columns = useMemo<MRT_ColumnDef<Person>[]>(
7 () => [
8 {
9 header: 'Status',
10 accessorFn: (originalRow) => (originalRow.isActive ? 'true' : 'false'), //must be strings
11 id: 'isActive',
12 filterVariant: 'checkbox',
13 Cell: ({ cell }) =>
14 cell.getValue() === 'true' ? 'Active' : 'Inactive',
15 size: 170,
16 },
17 {
18 accessorKey: 'name',
19 header: 'Name',
20 filterVariant: 'text', // default
21 size: 100,
22 },
23 {
24 accessorKey: 'age',
25 header: 'Age',
26 filterVariant: 'range',
27 filterFn: 'between',
28 size: 80,
29 },
30 {
31 accessorKey: 'salary',
32 header: 'Salary',
33 Cell: ({ cell }) =>
34 cell.getValue<number>().toLocaleString('en-US', {
35 style: 'currency',
36 currency: 'USD',
37 }),
38 filterVariant: 'range-slider',
39 filterFn: 'betweenInclusive', // default (or between)
40 muiFilterSliderProps: {
41 marks: true,
42 max: 200_000, //custom max (as opposed to faceted max)
43 min: 30_000, //custom min (as opposed to faceted min)
44 step: 10_000,
45 valueLabelFormat: (value) =>
46 value.toLocaleString('en-US', {
47 style: 'currency',
48 currency: 'USD',
49 }),
50 },
51 },
52 {
53 accessorKey: 'city',
54 header: 'City',
55 filterVariant: 'select',
56 filterSelectOptions: citiesList, //custom options list (as opposed to faceted list)
57 },
58 {
59 accessorKey: 'state',
60 header: 'State',
61 filterVariant: 'multi-select',
62 filterSelectOptions: usStateList, //custom options list (as opposed to faceted list)
63 },
64 ],
65 [],
66 );
67
68 return (
69 <MaterialReactTable
70 columns={columns}
71 data={data}
72 initialState={{ showColumnFilters: true }}
73 />
74 );
75};
76
77export default Example;
78

Faceted Values for Filter Variants

New in v1.13

Faceted values are a list of unique values for a column that gets generated under the hood from table data when the enableFacetedValues prop is set to true. These values can be used to populate the select dropdowns for the 'select' and 'multi-select' filter variants, or the min and max values for the 'range-slider' variant. This means that you no longer need to manually specify the filterSelectOptions prop for these variants manually, especially if you are using client-side filtering.


Tanner Linsley$100,000.00San FranciscoCalifornia
Kevin Vandy$80,000.00RichmondVirginia
John Doe$120,000.00RiversideSouth Carolina
Jane Doe$150,000.00San FranciscoCalifornia
John Smith$75,000.00Los AngelesCalifornia
Jane Smith$56,000.00BlacksburgVirginia
Samuel Jackson$90,000.00New YorkNew York

1-7 of 7

Source Code

1import React, { useMemo } from 'react';
2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
3import { data, Person } from './makeData';
4
5const Example = () => {
6 const columns = useMemo<MRT_ColumnDef<Person>[]>(
7 () => [
8 {
9 accessorKey: 'name',
10 header: 'Name',
11 filterVariant: 'text', // default
12 size: 100,
13 },
14 {
15 accessorKey: 'salary',
16 header: 'Salary',
17 Cell: ({ cell }) =>
18 cell.getValue<number>().toLocaleString('en-US', {
19 style: 'currency',
20 currency: 'USD',
21 }),
22 filterVariant: 'range-slider',
23 filterFn: 'betweenInclusive', // default (or between)
24 muiFilterSliderProps: {
25 //no need to specify min/max/step if using faceted values
26 marks: true,
27 step: 5_000,
28 valueLabelFormat: (value) =>
29 value.toLocaleString('en-US', {
30 style: 'currency',
31 currency: 'USD',
32 }),
33 },
34 },
35 {
36 accessorKey: 'city',
37 header: 'City',
38 filterVariant: 'select',
39 //no need to specify filterSelectOptions if using faceted values
40 },
41 {
42 accessorKey: 'state',
43 header: 'State',
44 filterVariant: 'multi-select',
45 //no need to specify filterSelectOptions if using faceted values
46 },
47 ],
48 [],
49 );
50
51 return (
52 <MaterialReactTable
53 columns={columns}
54 data={data}
55 enableFacetedValues
56 initialState={{ showColumnFilters: true }}
57 />
58 );
59};
60
61export default Example;
62

Custom Faceted Values

If you are using server-side pagination and filtering, you can still customize the faceted values output with the getFacetedUniqueValues and getFacetedMinMaxValues props.

<MaterialReactTable
columns={columns}
data={data}
enableFacetedValues={true}
//if using server-side pagination and filtering
getFacetedMinMaxValues={(table) => {
//fetch min and max values from server
return [minValue, maxValue];
}}
//if using server-side filtering
getFacetedUniqueValues={(table) => {
const uniqueValueMap = new Map<string, number>();
//fetch unique values from server, ideally including the count of each unique value
return uniqueValueMap;
}}
/>

Custom Filter Functions

You can specify either a pre-built filterFn that comes with Material React Table or pass in your own custom filter functions.

Custom Filter Functions Per Column

By default, Material React Table uses a fuzzy filtering algorithm based on the popular match-sorter library from Kent C. Dodds. However, Material React Table also comes with numerous other filter functions that you can specify per column in the filterFn column options.

Pre-built MRT Filter Functions

Pre-built filter functions from Material React Table include between, betweenInclusive, contains, empty, endsWith, equals, fuzzy, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, notEmpty, notEquals, and startsWith. View these algorithms here

Pre-built TanStack Table Filter Functions

Pre-built filter functions from TanStack Table include includesString, includesStringSensitive, equalsString, equalsStringSensitive, arrIncludes, arrIncludesAll, arrIncludesSome, weakEquals, and inNumberRange. View more information about these algorithms in the TanStack Table Filter docs.

You can specify either a pre-built filter function, from Material React Table or TanStack Table, or you can even specify your own custom filter function in the filterFn column option.

const columns = [
{
accessorKey: 'firstName',
header: 'First Name',
// using a prebuilt filter function from Material React Table
filterFn: 'startsWith',
},
{
accessorKey: 'middleName',
header: 'Middle Name',
// using a prebuilt filter function from TanStack Table
filterFn: 'includesStringSensitive',
},
{
accessorKey: 'lastName',
header: 'Last Name',
// custom filter function
filterFn: (row, id, filterValue) =>
row.getValue(id).startsWith(filterValue),
},
];

If you provide a custom filter function, it must have the following signature:

(row: Row<TData>, id: string, filterValue: string | number) => boolean;

This function will be used to filter 1 row at a time and should return a boolean indicating whether or not that row passes the filter.

Add Custom Filter Functions

You can add custom filter functions to the filterFns prop. These will be available to all columns to use. The filterFn prop on a column will override any filter function with the same name in the filterFns prop.

const columns = [
{
accessorKey: 'name',
header: 'Name',
filterFn: 'customFilterFn',
},
];
return (
<MaterialReactTable
data={data}
columns={columns}
filterFns={{
customFilterFn: (row, id, filterValue) => {
return row.customField === value;
},
}}
/>
);

Filter Modes

Enable Column Filter Modes (Filter Switching)

If you want to let the user switch between multiple different filter modes from a drop-down menu on the Filter Textfield, you can enable that with the enableColumnFilterModes prop or column option. This will enable the filter icon in the filter text field to open a drop-down menu with the available filter modes when clicked.

<MaterialReactTable columns={columns} data={data} enableColumnFilterModes />

Customize Filter Modes

You can narrow down the available filter mode options by setting the columnFilterModeOptions prop or a column specific columnFilterModeOptions option.

const columns = [
{
accessorKey: 'firstName',
header: 'First Name',
columnFilterModeOptions: ['fuzzy', 'contains', 'startsWith'],
},
{
accessorKey: 'age',
header: 'Age',
columnFilterModeOptions: ['between', 'lessThan', 'greaterThan'],
},
];

Render Custom Filter Mode Menu

You can also render custom menu items in the filter mode drop-down menu by setting the renderColumnFilterModeMenuItems prop or column option. This option is a function that takes in the column and returns an array of MenuItem components. This is useful if you want to add custom filter modes that are not included in Material React Table, or if you just want to render the menu in your own custom way

const columns = [
{
accessorKey: 'firstName',
header: 'First Name',
renderColumnFilterModeMenuItems: ({ column, onSelectFilterMode }) => [
<MenuItem
key="startsWith"
onClick={() => onSelectFilterMode('startsWith')}
>
Start With
</MenuItem>,
<MenuItem
key="endsWith"
onClick={() => onSelectFilterMode('yourCustomFilterFn')}
>
Your Custom Filter Fn
</MenuItem>,
],
},
];
return (
<MaterialReactTable
columns={columns}
data={data}
enableColumnFilterModes
// renderColumnFilterModeMenuItems could go here if you want to apply to all columns
/>
);

1HughJayMungus42
2LeroyLeroyJenkins51
3CandiceDeniseNutella27
4MicahHenryJohnson32

1-4 of 4

Source Code

1import React, { useMemo } from 'react';
2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
3import { MenuItem } from '@mui/material';
4import { data, type Person } from './makeData';
5
6const Example = () => {
7 const columns = useMemo<MRT_ColumnDef<Person>[]>(
8 () => [
9 {
10 accessorKey: 'id',
11 enableColumnFilterModes: false, //disable changing filter mode for this column
12 filterFn: 'equals', //set filter mode to equals
13 header: 'ID',
14 },
15 {
16 accessorKey: 'firstName', //normal, all filter modes are enabled
17 header: 'First Name',
18 },
19 {
20 accessorKey: 'middleName',
21 enableColumnFilterModes: false, //disable changing filter mode for this column
22 filterFn: 'startsWith', //even though changing the mode is disabled, you can still set the default filter mode
23 header: 'Middle Name',
24 },
25 {
26 accessorKey: 'lastName',
27 header: 'Last Name',
28 //if you do not want to use the default filter modes, you can provide your own and render your own menu
29 renderColumnFilterModeMenuItems: ({ onSelectFilterMode }) => [
30 <MenuItem key="0" onClick={() => onSelectFilterMode('contains')}>
31 <div>Contains</div>
32 </MenuItem>,
33 <MenuItem
34 key="1"
35 onClick={() => onSelectFilterMode('customFilterFn')}
36 >
37 <div>Custom Filter Fn</div>
38 </MenuItem>,
39 ],
40 },
41 {
42 accessorKey: 'age',
43 columnFilterModeOptions: ['between', 'greaterThan', 'lessThan'], //only allow these filter modes
44 filterFn: 'between',
45 header: 'Age',
46 },
47 ],
48 [],
49 );
50
51 return (
52 <MaterialReactTable
53 columns={columns}
54 data={data}
55 enableColumnFilterModes //enable changing filter mode for all columns unless explicitly disabled in a column def
56 initialState={{ showColumnFilters: true }} //show filters by default
57 filterFns={{
58 customFilterFn: (row, id, filterValue) => {
59 return row.getValue(id) === filterValue;
60 },
61 }}
62 localization={
63 {
64 filterCustomFilterFn: 'Custom Filter Fn',
65 } as any
66 }
67 />
68 );
69};
70
71export default Example;
72

Expanded Leaf Row Filtering Options

If you are using the filtering features along-side either the grouping or expanding features, then there are a few behaviors and customizations you should be aware of.

Check out the Expanded Leaf Row Filtering Behavior docs to learn more about the filterFromLeafRows and maxLeafRowFilterDepth props.

Manual Server-Side Column Filtering

A very common use case when you have a lot of data is to filter the data on the server, instead of client-side. In this case, you will want to set the manualFiltering prop to true and manage the columnFilters state yourself like so (can work in conjunction with manual global filtering).

// You can manage and have control over the columnFilters state yourself
const [columnFilters, setColumnFilters] = useState([]);
const [data, setData] = useState([]); //data will get updated after re-fetching
useEffect(() => {
const fetchData = async () => {
// send api requests when columnFilters state changes
const filteredData = await fetch();
setData([...filteredData]);
};
}, [columnFilters]);
return (
<MaterialReactTable
columns={columns}
data={data} // this will already be filtered on the server
manualFiltering //turn off client-side filtering
onColumnFiltersChange={setColumnFilters} //hoist internal columnFilters state to your state
state={{ columnFilters }} //pass in your own managed columnFilters state
/>
);

Specifying manualFiltering turns off all client-side filtering and assumes that the data you pass to <MaterialReactTable /> is already filtered.

Here is the full Remote Data example featuring server-side filtering, pagination, and sorting.


0-0 of 0

Source Code

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

Customize Material UI Filter components

You can customize the Material UI filter components by setting the muiFilterTextFieldProps prop or column option.

You can also turn a filter textfield into a select dropdown by setting the filterSelectOptions prop or column option.


1HughMungusMale42
2LeroyJenkinsMale51
3CandiceNutellaFemale27
4MicahJohnsonOther32

1-4 of 4

Source Code

1import React, { useMemo } from 'react';
2import { MaterialReactTable, type MRT_ColumnDef } from 'material-react-table';
3
4export type Person = {
5 id: number;
6 firstName: string;
7 lastName: string;
8 gender: string;
9 age: number;
10};
11
12const Example = () => {
13 const columns = useMemo<MRT_ColumnDef<Person>[]>(
14 () => [
15 {
16 accessorKey: 'id',
17 header: 'ID',
18 muiFilterTextFieldProps: { placeholder: 'ID' },
19 },
20 {
21 accessorKey: 'firstName',
22 header: 'First Name',
23 },
24 {
25 accessorKey: 'lastName',
26 header: 'Last Name',
27 },
28 {
29 accessorKey: 'gender',
30 header: 'Gender',
31 filterFn: 'equals',
32 filterSelectOptions: [
33 { text: 'Male', value: 'Male' },
34 { text: 'Female', value: 'Female' },
35 { text: 'Other', value: 'Other' },
36 ],
37 filterVariant: 'select',
38 },
39 {
40 accessorKey: 'age',
41 header: 'Age',
42 filterVariant: 'range',
43 },
44 ],
45 [],
46 );
47
48 const data = useMemo<Person[]>(
49 //data definitions...
82 );
83
84 return (
85 <MaterialReactTable
86 columns={columns}
87 data={data}
88 initialState={{ showColumnFilters: true }} //show filters by default
89 muiFilterTextFieldProps={{
90 sx: { m: '0.5rem 0', width: '100%' },
91 variant: 'outlined',
92 }}
93 />
94 );
95};
96
97export default Example;
98

Custom Filter Components

If you need custom filter components that are much more complex than text-boxes and dropdowns, you can create and pass in your own filter components using the Filter column option.

View Extra Storybook Examples