Filtering
Built-in per-column filter popups with operator selection, two-condition AND/OR logic, and support for text, number, and date column types.
Column filters — text, number, and date
Click the filter icon in any column header. Pick an operator, enter a value, then click Apply. Try salary ≥ 130000, or filter hired Before 2021-01-01.
import DataTable, { type TableColumn } from 'react-data-table-component';
interface Employee {
id: number;
name: string;
department: string;
salary: number;
hired: string;
}
const data: Employee[] = [
{ id: 1, name: 'Aria Chen', department: 'Engineering', salary: 155000, hired: '2019-03-12' },
{ id: 2, name: 'Marcus Webb', department: 'Product', salary: 132000, hired: '2020-07-01' },
{ id: 3, name: 'Priya Kapoor', department: 'Design', salary: 118000, hired: '2021-01-15' },
{ id: 4, name: 'Jordan Ellis', department: 'Analytics', salary: 143000, hired: '2018-11-30' },
{ id: 5, name: 'Sam Rivera', department: 'Engineering', salary: 128000, hired: '2022-04-22' },
{ id: 6, name: 'Taylor Brooks', department: 'Sales', salary: 97000, hired: '2023-02-08' },
{ id: 7, name: 'Morgan Lee', department: 'Engineering', salary: 162000, hired: '2017-09-05' },
{ id: 8, name: 'Casey Park', department: 'Design', salary: 109000, hired: '2022-11-19' },
{ id: 9, name: 'Drew Santos', department: 'Product', salary: 138000, hired: '2020-03-30' },
{ id: 10, name: 'Avery Johnson', department: 'Sales', salary: 104000, hired: '2021-08-14' },
];
const columns: TableColumn<Employee>[] = [
{ id: 'name', name: 'Name', selector: r => r.name, sortable: true, filterable: true },
{ id: 'dept', name: 'Department', selector: r => r.department, filterable: true },
{
id: 'salary', name: 'Salary', selector: r => r.salary,
format: r => `$${r.salary.toLocaleString()}`,
right: true, sortable: true, filterable: true, filterType: 'number',
},
{ id: 'hired', name: 'Hired', selector: r => r.hired, sortable: true, filterable: true, filterType: 'date' },
];
export default function App() {
return <DataTable columns={columns} data={data} highlightOnHover />;
} Quick start
Add filterable: true and a stable id to any column. A filter
icon appears in the column header. Filters across columns combine with AND. A row must
pass every active filter to appear.
const columns: TableColumn<Row>[] = [
{ id: 'name', name: 'Name', selector: r => r.name, filterable: true },
];
<DataTable columns={columns} data={data} /> Filter types
Set filterType to get the right operator set and input widget. Defaults to "text".
const columns: TableColumn<Row>[] = [
{ id: 'name', name: 'Name', selector: r => r.name, filterable: true },
{ id: 'score', name: 'Score', selector: r => r.score, filterable: true, filterType: 'number' },
{ id: 'dob', name: 'Birth date', selector: r => r.dob, filterable: true, filterType: 'date' },
]; filterType | Default operator | Input | Operators |
|---|---|---|---|
"text" (default) | Contains | Text | Contains, Does not contain, Equals, Does not equal, Begins with, Ends with, Blank, Not blank |
"number" | Equals | Number | Equals, Does not equal, Greater than, ≥, Less than, ≤, Between, Blank, Not blank |
"date" | Equals | Date | Equals, Before, After, Between, Blank, Not blank |
Blank / Not blank match on empty cells and need no value input.
Between (number and date) shows two value inputs for inclusive bounds.
For "date" columns, selector should return an ISO string ("2024-03-15") or any value parseable by new Date().
Two conditions per column
Each filter popup has a + Add condition link. Adding a second condition reveals an AND / OR toggle. AND means both conditions must match; OR means either must match.
import type { FilterState } from 'react-data-table-component';
// The shape of one column's filter state
const filter: FilterState = {
condition1: { operator: 'startsWith', value: 'J' },
condition2: { operator: 'endsWith', value: 'son' },
logic: 'AND', // 'AND' | 'OR' — defaults to 'AND'
}; Apply / Clear behaviour
Filters apply only when the user clicks Apply. Typing does not immediately re-filter. This avoids jarring mid-keystroke changes on large datasets. Clicking Clear resets the column's filter and applies immediately.
Custom filter function
Override built-in operator logic per column with filterFunction. It receives
the full FilterState so both conditions are available:
import type { TableColumn, FilterState } from 'react-data-table-component';
const columns: TableColumn<Row>[] = [
{
id: 'tags',
name: 'Tags',
selector: r => r.tags.join(', '),
filterable: true,
filterFunction: (row, filter) => {
const term = (filter.condition1.value ?? '').toLowerCase();
return row.tags.some(tag => tag.toLowerCase().includes(term));
},
},
]; Controlled mode
Pass filterValues and onFilterChange to own the filter state
yourself. Useful for persisting it in a URL or resetting it programmatically.
onFilterChange fires on every Apply or Clear click.
import { useState } from 'react';
import DataTable, { type FilterState } from 'react-data-table-component';
function App() {
const [filterValues, setFilterValues] = useState<Record<string | number, FilterState>>({});
const [resetPage, setResetPage] = useState(false);
function handleFilterChange(columnId: string | number, filter: FilterState) {
setFilterValues(prev => ({ ...prev, [columnId]: filter }));
setResetPage(v => !v); // jump back to page 1 after each filter
}
return (
<DataTable
columns={columns}
data={data}
filterValues={filterValues}
onFilterChange={handleFilterChange}
pagination
paginationResetDefaultPage={resetPage}
/>
);
} Utility exports
import { emptyFilterState, isFilterActive, type FilterState } from 'react-data-table-component';
// Create a default-empty FilterState for a given type
emptyFilterState('number'); // { condition1: { operator: 'equals' } }
emptyFilterState('text'); // { condition1: { operator: 'contains' } }
// Check whether a FilterState is actually filtering anything
isFilterActive({ condition1: { operator: 'contains' } }); // false — no value
isFilterActive({ condition1: { operator: 'contains', value: 'a' } }); // true
isFilterActive({ condition1: { operator: 'blank' } }); // true — no value needed Headless usage
Use useColumnFilter directly when building a custom table with the headless hooks.
See Headless hooks for the full API.
import { useColumnFilter, type FilterState } from 'react-data-table-component';
const { filterValues, handleFilterChange, filteredData } = useColumnFilter(columns);
// Call handleFilterChange when the user applies a filter in your custom UI
function onApply(columnId: string | number, filter: FilterState) {
handleFilterChange(columnId, filter);
}
// Apply all active filters before rendering rows
const rows = filteredData(tableRows);