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.

Name
Department
Salary
Hired
Aria Chen
Engineering
$155,000
2019-03-12
Avery Johnson
Sales
$104,000
2021-08-14
Casey Park
Design
$109,000
2022-11-19
Drew Santos
Product
$138,000
2020-03-30
Jordan Ellis
Analytics
$143,000
2018-11-30
Marcus Webb
Product
$132,000
2020-07-01
Morgan Lee
Engineering
$162,000
2017-09-05
Priya Kapoor
Design
$118,000
2021-01-15
Sam Rivera
Engineering
$128,000
2022-04-22
Taylor Brooks
Sales
$97,000
2023-02-08

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);