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 Table Options
# | Prop Name | Type | Default Value | More Info Links | |
---|---|---|---|---|---|
1 |
| MRT Column Filtering Docs | |||
2 |
|
| MRT Column Filtering Docs | ||
3 |
|
| MRT Column Filtering Docs | ||
4 |
|
| TanStack Filters Docs | ||
5 |
|
| MRT Column Filtering Docs | ||
6 |
|
| TanStack Filters Docs | ||
7 |
| TanStack Table Filters Docs | |||
8 |
|
| TanStack Filtering Docs | ||
9 |
| TanStack Table Filters Docs | |||
10 |
| TanStack Table Filters Docs | |||
11 |
| TanStack Table Filters Docs | |||
12 |
| TanStack Table Filters Docs | |||
13 |
| TanStack Table Filters Docs | |||
14 |
|
| TanStack Table Filtering Docs | ||
15 |
| Material UI Autocomplete Props | |||
16 |
| Material UI Checkbox Props | |||
17 |
| MUI X DatePicker Props | |||
18 |
| MUI X DateTimePicker Props | |||
19 |
| Material UI Slider Props | |||
20 |
| Material UI TextField Props | |||
21 |
| MUI X TimePicker Props | |||
22 |
| ||||
23 |
| TanStack Table Filter Docs | |||
24 |
| ||||
25 |
| ||||
Relevant Column Options
# | Column Option | Type | Default Value | More Info Links | |
---|---|---|---|---|---|
1 |
| ||||
2 |
| MRT Column Filtering Docs | |||
3 |
| MRT Column Filtering Docs | |||
4 |
| MRT Column Filtering Docs | |||
5 |
| MRT Column Filtering Docs | |||
6 |
|
| |||
7 |
| ||||
8 |
|
| |||
9 |
| MUI X DatePicker Props | |||
10 |
| Material UI Checkbox Props | |||
11 |
| MUI X DatePicker Props | |||
12 |
| MUI X DateTimePicker Props | |||
13 |
| Material UI Slider Props | |||
14 |
| Material UI TextField Props | |||
15 |
| MUI X TimePicker Props | |||
16 | |||||
Relevant State Options
# | State Option | Type | Default Value | More Info Links | |
---|---|---|---|---|---|
1 |
| ||||
2 |
|
| TanStack Table Filters Docs | ||
3 |
|
| |||
Disable Filtering Features
Various subsets of filtering features can be disabled. If you want to disable filtering completely, you can set the enableColumnFilters
table option 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.
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'autocomplete'
- shows an autocomplete text field with the options from faceted values or specified infilterSelectOptions
array.'select'
- shows a select dropdown with the options from faceted values or specified infilterSelectOptions
array.'multi-select'
- shows a select dropdown with the options from faceted values or specified infilterSelectOptions
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'date'
- shows a date picker for filtering by date values'datetime'
- shows a date and time picker for filtering by date and time values'date-range'
- shows a date range picker for filtering by date ranges'datetime-range'
- shows a date and time range picker for filtering by date and time ranges'time'
- shows a time picker for filtering by time values'time-range'
- shows a time range picker for filtering by time ranges'checkbox'
- shows a checkbox for filtering by'true'
or'false'
values
'autocomplete'
,'date'
, and'date-range'
, variants are new in v2.0.0
datetime
,datetime-range
,time
, andtime-range
variants are new in v2.4.0
Status | Name | Salary | Age | City Filter by City | State Filter by State | Hire Date | Arrival Time | Departure Time |
---|---|---|---|---|---|---|---|---|
Active | Tanner Linsley | $100,000.00 | 42 | San Francisco | California | 2/23/2016 | 2/23/2016 6:25:43 PM | 3:40:45 AM |
Active | Kevin Vandy | $80,000.00 | 51 | Richmond | Virginia | 2/23/2019 | 2/23/2019 6:21:43 PM | 10:02:51 AM |
Inactive | John Doe | $120,000.00 | 27 | Riverside | South Carolina | 2/23/2014 | 2/23/2014 6:25:43 PM | 9:57:23 AM |
Active | Jane Doe | $150,000.00 | 32 | San Francisco | California | 2/25/2015 | 2/25/2015 6:25:43 PM | 1:51:56 PM |
Inactive | John Smith | $75,000.00 | 42 | Los Angeles | California | 6/11/2023 | 6/11/2023 6:25:43 PM | 4:23:29 AM |
Active | Jane Smith | $56,000.00 | 51 | Blacksburg | Virginia | 2/23/2019 | 2/23/2019 6:21:43 PM | 12:10:32 PM |
Inactive | Samuel Jackson | $90,000.00 | 27 | New York | New York | 2/23/2010 | 2/23/2010 6:25:43 PM | 9:41:47 PM |
1import { useMemo } from 'react';2import {3 MaterialReactTable,4 useMaterialReactTable,5 type MRT_ColumnDef,6} from 'material-react-table';7import { citiesList, data, type Person, usStateList } from './makeData';89const Example = () => {10 const columns = useMemo<MRT_ColumnDef<Person>[]>(11 () => [12 {13 header: 'Status',14 accessorFn: (originalRow) => (originalRow.isActive ? 'true' : 'false'), //must be strings15 id: 'isActive',16 filterVariant: 'checkbox',17 Cell: ({ cell }) =>18 cell.getValue() === 'true' ? 'Active' : 'Inactive',19 size: 170,20 },21 {22 accessorKey: 'name',23 header: 'Name',24 filterVariant: 'text', // default25 size: 200,26 },27 {28 accessorKey: 'salary',29 header: 'Salary',30 Cell: ({ cell }) =>31 cell.getValue<number>().toLocaleString('en-US', {32 style: 'currency',33 currency: 'USD',34 }),35 filterVariant: 'range-slider',36 filterFn: 'betweenInclusive', // default (or between)37 muiFilterSliderProps: {38 marks: true,39 max: 200_000, //custom max (as opposed to faceted max)40 min: 30_000, //custom min (as opposed to faceted min)41 step: 10_000,42 valueLabelFormat: (value) =>43 value.toLocaleString('en-US', {44 style: 'currency',45 currency: 'USD',46 }),47 },48 },49 {50 accessorKey: 'age',51 header: 'Age',52 filterVariant: 'range',53 filterFn: 'between',54 size: 80,55 },56 {57 accessorKey: 'city',58 header: 'City',59 filterVariant: 'select',60 filterSelectOptions: citiesList, //custom options list (as opposed to faceted list)61 },62 {63 accessorKey: 'state',64 header: 'State',65 filterVariant: 'multi-select',66 filterSelectOptions: usStateList, //custom options list (as opposed to faceted list)67 },68 {69 accessorFn: (originalRow) => new Date(originalRow.hireDate), //convert to date for sorting and filtering70 id: 'hireDate',71 header: 'Hire Date',72 filterVariant: 'date-range',73 Cell: ({ cell }) => cell.getValue<Date>().toLocaleDateString(), // convert back to string for display74 },75 {76 accessorFn: (originalRow) => new Date(originalRow.arrivalTime), //convert to date for sorting and filtering77 id: 'arrivalTime',78 header: 'Arrival Time',79 filterVariant: 'datetime-range',80 Cell: ({ cell }) =>81 `${cell.getValue<Date>().toLocaleDateString()} ${cell82 .getValue<Date>()83 .toLocaleTimeString()}`, // convert back to string for display84 },85 {86 accessorFn: (originalRow) => new Date(originalRow.departureTime), //convert to date for sorting and filtering87 id: 'departureTime',88 header: 'Departure Time',89 filterVariant: 'time-range',90 Cell: ({ cell }) => cell.getValue<Date>().toLocaleTimeString(), // convert back to string for display91 },92 ],93 [],94 );9596 const table = useMaterialReactTable({97 columns,98 data,99 initialState: { showColumnFilters: true },100 });101102 return <MaterialReactTable table={table} />;103};104105//Date Picker Imports - these should just be in your Context Provider106import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';107import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';108109const ExampleWithLocalizationProvider = () => (110 //App.tsx or AppProviders file111 <LocalizationProvider dateAdapter={AdapterDayjs}>112 <Example />113 </LocalizationProvider>114);115116export default ExampleWithLocalizationProvider;117
Faceted Values for Filter Variants
Faceted values are a list of unique values for a column that gets generated under the hood from table data when the enableFacetedValues
table option 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
table option for these variants manually, especially if you are using client-side filtering.
Name | Salary | City Filter by City | State Filter by State |
---|---|---|---|
Tanner Linsley | $100,000.00 | San Francisco | California |
Kevin Vandy | $80,000.00 | Richmond | Virginia |
John Doe | $120,000.00 | Riverside | South Carolina |
Jane Doe | $150,000.00 | San Francisco | California |
John Smith | $75,000.00 | Los Angeles | California |
Jane Smith | $56,000.00 | Blacksburg | Virginia |
Samuel Jackson | $90,000.00 | New York | New York |
1import { useMemo } from 'react';2import {3 MaterialReactTable,4 useMaterialReactTable,5 type MRT_ColumnDef,6} from 'material-react-table';7import { data, type Person } from './makeData';89const Example = () => {10 const columns = useMemo<MRT_ColumnDef<Person>[]>(11 () => [12 {13 accessorKey: 'name',14 header: 'Name',15 filterVariant: 'autocomplete', // default16 size: 100,17 },18 {19 accessorKey: 'salary',20 header: 'Salary',21 Cell: ({ cell }) =>22 cell.getValue<number>().toLocaleString('en-US', {23 style: 'currency',24 currency: 'USD',25 }),26 filterVariant: 'range-slider',27 filterFn: 'betweenInclusive', // default (or between)28 muiFilterSliderProps: {29 //no need to specify min/max/step if using faceted values30 marks: true,31 step: 5_000,32 valueLabelFormat: (value) =>33 value.toLocaleString('en-US', {34 style: 'currency',35 currency: 'USD',36 }),37 },38 },39 {40 accessorKey: 'city',41 header: 'City',42 filterVariant: 'select',43 //no need to specify filterSelectOptions if using faceted values44 },45 {46 accessorKey: 'state',47 header: 'State',48 filterVariant: 'multi-select',49 //no need to specify filterSelectOptions if using faceted values50 },51 ],52 [],53 );5455 const table = useMaterialReactTable({56 columns,57 data,58 enableFacetedValues: true,59 initialState: { showColumnFilters: true },60 });6162 return <MaterialReactTable table={table} />;63};6465export default Example;66
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.
const table = useMaterialReactTable({columns,data,enableFacetedValues: true,//if using server-side pagination and filteringgetFacetedMinMaxValues: (table) => {//fetch min and max values from serverreturn [minValue, maxValue];},//if using server-side filteringgetFacetedUniqueValues: (table) => {const uniqueValueMap = new Map<string, number>();//fetch unique values from server, ideally including the count of each unique valuereturn uniqueValueMap;},})
Column Filter Display Modes
By default, column filters inputs show below the column header. You can switch to a more "excel-like" UI by setting the columnFilterDisplayMode
table option to 'popover'
. This will show a filter icon in the column header that can be clicked to open a popover with the filter input.
const table = useMaterialReactTable({columns,data,columnFilterDisplayMode: 'popover', //filter inputs will show in a popover (like excel)});
Alternatively, if you want to render your own column filter UI in a separate sidebar, but still want to use the built-in filtering functionality, you can set the columnFilterDisplayMode
table option to 'custom'
.
const table = useMaterialReactTable({columns,data,columnFilterDisplayMode: 'custom', //render your own column filter UI (e.g. in a sidebar)});
ID | First Name | Last Name | Gender | Age |
---|---|---|---|---|
1 | Hugh | Mungus | Male | 42 |
2 | Leroy | Jenkins | Male | 51 |
3 | Candice | Nutella | Female | 27 |
4 | Micah | Johnson | Other | 32 |
1import { useMemo } from 'react';2import {3 MaterialReactTable,4 useMaterialReactTable,5 type MRT_ColumnDef,6} from 'material-react-table';7import { data, type Person } from './makeData';89const Example = () => {10 const columns = useMemo<MRT_ColumnDef<Person>[]>(11 () => [12 {13 accessorKey: 'id',14 header: 'ID',15 },16 {17 accessorKey: 'firstName',18 header: 'First Name',19 },20 {21 accessorKey: 'lastName',22 header: 'Last Name',23 },24 {25 accessorKey: 'gender',26 header: 'Gender',27 filterFn: 'equals',28 filterSelectOptions: ['Male', 'Female', 'Other'],29 filterVariant: 'select',30 },31 {32 accessorKey: 'age',33 header: 'Age',34 filterVariant: 'range',35 },36 ],37 [],38 );3940 const table = useMaterialReactTable({41 columns,42 data,43 columnFilterDisplayMode: 'popover',44 });4546 return <MaterialReactTable table={table} />;47};4849export default Example;50
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
, andstartsWith
. 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
, andinNumberRange
. 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 TablefilterFn: 'startsWith',},{accessorKey: 'middleName',header: 'Middle Name',// using a prebuilt filter function from TanStack TablefilterFn: 'includesStringSensitive',},{accessorKey: 'lastName',header: 'Last Name',// custom filter functionfilterFn: (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
table option. These will be available to all columns to use. The filterFn
table option on a column will override any filter function with the same name in the filterFns
table option.
const columns = [{accessorKey: 'name',header: 'Name',filterFn: 'customFilterFn',},];const table = useMaterialReactTable({columns,data,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
table option 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.
const table = useMaterialReactTable({columns,data,enableColumnFilterModes: true,});
Customize Filter Modes
You can narrow down the available filter mode options by setting the columnFilterModeOptions
table option 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
table option 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 }) => [<MenuItemkey="startsWith"onClick={() => onSelectFilterMode('startsWith')}>Start With</MenuItem>,<MenuItemkey="endsWith"onClick={() => onSelectFilterMode('yourCustomFilterFn')}>Your Custom Filter Fn</MenuItem>,],},];const table = useMaterialReactTable({columns,data,enableColumnFilterModes: true,// renderColumnFilterModeMenuItems could go here if you want to apply to all columns});return <MaterialReactTable table={table} />;
ID | First Name | Middle Name | Last Name | Age |
---|---|---|---|---|
1 | Hugh | Jay | Mungus | 42 |
2 | Leroy | Leroy | Jenkins | 51 |
3 | Candice | Denise | Nutella | 27 |
4 | Micah | Henry | Johnson | 32 |
1import { useMemo } from 'react';2import {3 MaterialReactTable,4 useMaterialReactTable,5 type MRT_ColumnDef,6} from 'material-react-table';7import { MenuItem } from '@mui/material';8import { data, type Person } from './makeData';910const Example = () => {11 const columns = useMemo<MRT_ColumnDef<Person>[]>(12 () => [13 {14 accessorKey: 'id',15 enableColumnFilterModes: false, //disable changing filter mode for this column16 filterFn: 'equals', //set filter mode to equals17 header: 'ID',18 },19 {20 accessorKey: 'firstName', //normal, all filter modes are enabled21 header: 'First Name',22 },23 {24 accessorKey: 'middleName',25 enableColumnFilterModes: false, //disable changing filter mode for this column26 filterFn: 'startsWith', //even though changing the mode is disabled, you can still set the default filter mode27 header: 'Middle Name',28 },29 {30 accessorKey: 'lastName',31 header: 'Last Name',32 //if you do not want to use the default filter modes, you can provide your own and render your own menu33 renderColumnFilterModeMenuItems: ({ onSelectFilterMode }) => [34 <MenuItem key="0" onClick={() => onSelectFilterMode('contains')}>35 <div>Contains</div>36 </MenuItem>,37 <MenuItem38 key="1"39 onClick={() => onSelectFilterMode('customFilterFn')}40 >41 <div>Custom Filter Fn</div>42 </MenuItem>,43 ],44 },45 {46 accessorKey: 'age',47 columnFilterModeOptions: ['between', 'greaterThan', 'lessThan'], //only allow these filter modes48 filterFn: 'between',49 header: 'Age',50 },51 ],52 [],53 );5455 const table = useMaterialReactTable({56 columns,57 data,58 enableColumnFilterModes: true, //enable changing filter mode for all columns unless explicitly disabled in a column def59 initialState: { showColumnFilters: true }, //show filters by default60 filterFns: {61 customFilterFn: (row, id, filterValue) => {62 return row.getValue(id) === filterValue;63 },64 },65 localization: {66 filterCustomFilterFn: 'Custom Filter Fn',67 } as any,68 });6970 return <MaterialReactTable table={table} />;71};7273export default Example;74
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
table option 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 yourselfconst [columnFilters, setColumnFilters] = useState([]);const [data, setData] = useState([]); //data will get updated after re-fetchinguseEffect(() => {const fetchData = async () => {// send api requests when columnFilters state changesconst filteredData = await fetch();setData([...filteredData]);};}, [columnFilters]);const table = useMaterialReactTable({columns,data, // this will already be filtered on the servermanualFiltering: true, //turn off client-side filteringonColumnFiltersChange: setColumnFilters, //hoist internal columnFilters state to your statestate: { columnFilters }, //pass in your own managed columnFilters state});return <MaterialReactTable table={table} />;
Specifying
manualFiltering
turns off all client-side filtering and assumes that thedata
you pass to<MaterialReactTable />
is already filtered.
See either the React Query or useEffect fetching examples to see fully server-side filtering, pagination, and sorting in action.
Customize Material UI Filter components
You can customize the Material UI filter components by setting the muiFilterTextFieldProps
table option or column option.
You can also turn a filter textfield into a select dropdown by setting the filterSelectOptions
table option or column option.
ID | First Name | Last Name | Gender Filter by Gender | Age |
---|---|---|---|---|
1 | Hugh | Mungus | Male | 42 |
2 | Leroy | Jenkins | Male | 51 |
3 | Candice | Nutella | Female | 27 |
4 | Micah | Johnson | Other | 32 |
1import { useMemo } from 'react';2import {3 MaterialReactTable,4 useMaterialReactTable,5 type MRT_ColumnDef,6} from 'material-react-table';78export type Person = {9 id: number;10 firstName: string;11 lastName: string;12 gender: string;13 age: number;14};1516const Example = () => {17 const columns = useMemo<MRT_ColumnDef<Person>[]>(18 () => [19 {20 accessorKey: 'id',21 header: 'ID',22 muiFilterTextFieldProps: { placeholder: 'ID' },23 },24 {25 accessorKey: 'firstName',26 header: 'First Name',27 },28 {29 accessorKey: 'lastName',30 header: 'Last Name',31 },32 {33 accessorKey: 'gender',34 header: 'Gender',35 filterFn: 'equals',36 filterSelectOptions: [37 { label: 'Male', value: 'Male' },38 { label: 'Female', value: 'Female' },39 { label: 'Other', value: 'Other' },40 ],41 filterVariant: 'select',42 },43 {44 accessorKey: 'age',45 header: 'Age',46 filterVariant: 'range',47 },48 ],49 [],50 );5152 const data = useMemo<Person[]>(53 //data definitions...86 );8788 const table = useMaterialReactTable({89 columns,90 data,91 initialState: { showColumnFilters: true },92 muiFilterTextFieldProps: {93 sx: { m: '0.5rem 0', width: '100%' },94 variant: 'outlined',95 },96 });9798 return <MaterialReactTable table={table} />;99};100101export default Example;102
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.
Filter Match Highlighting
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
table option 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
table option to false
.
const table = useMaterialReactTable({columns,data,enableFilterMatchHighlighting: false,});
View Extra Storybook Examples