Examples › Searching and filtering

Adjust the array of records you’re feeding to Mantine DataTable based on your own logic in order to perform searching and filtering.
In order to support column-based filtering you can use the filter and filtering column properties.
Here’s a possible (rather naive and rough around the edges) implementation:

Name
Department name
Company
Birth date
Age
Jerald HowellIndustrialRunte IncMay 21 195074
Kathleen RueckerComputersShanahan, Robel and BeierDec 19 194380
Erica VolkmanToysGoyette IncJan 29 195569
Clifford OberbrunnerAutomotiveRau - O'HaraMar 06 197945
Alison KlingJeweleryGoyette IncJan 27 199727
Sue ZiemeBooksCummerata - KuhlmanSep 12 196064
Felicia GleasonShoesDoyle, Hodkiewicz and O'ConnellMar 09 197747
Alfredo ZemlakGamesRunte IncNov 12 198836
Emily BartolettiAutomotiveRau - O'HaraJan 05 196856
Delores ReynoldsIndustrialRunte IncJun 04 200420
Louis SchambergerToolsCummerata - KuhlmanSep 07 199430
Beverly HellerBeautyRunte IncNov 29 200122
Eugene FeestKidsGoyette IncFeb 20 195470
Martin BahringerBeautyRau - O'HaraMay 26 194579
Ellis MillerElectronicsConnelly, Feest and HodkiewiczMay 24 195074
Gloria ColeHomeDoyle, Hodkiewicz and O'ConnellDec 09 199627
Linda WittingBabyDoyle, Hodkiewicz and O'ConnellMay 16 196559
Gregg KutchMoviesShanahan, Robel and BeierNov 28 198637
Mamie RaynorGroceryCummerata - KuhlmanNov 05 199232
Erick BruenElectronicsGoyette IncSep 26 195272
Faith LangworthClothingRunte IncNov 27 198340
Alicia LeannonSportsFeest, Bogan and HerzogDec 27 200518
Boyd MohrJeweleryGoyette IncJun 18 195173
Lindsey HeidenreichGamesShanahan, Robel and BeierJul 13 199727
Elsa MarvinBooksTillman - JacobiOct 07 198242
Debbie HagenesClothingRunte IncJan 24 196856
Lionel McCulloughKidsGoldner, Rohan and LehnerFeb 23 198638
Kim LebsackJeweleryCummerata - KuhlmanJun 11 197054
Rolando WeissnatHomeRau - O'HaraApr 25 195173
Jacqueline LeschGamesRunte IncJul 22 197846
Felix StokesKidsGoyette IncMar 21 198440
Renee TillmanIndustrialGoldner, Rohan and LehnerNov 24 195371
Richard WatsicaOutdoorsRunte IncJun 10 197153
Nathan WolfGamesGoldner, Rohan and LehnerJul 02 199826
Jonathan Keebler-CronaMusicGoyette IncOct 22 200222
Kathleen SpinkaJeweleryGoldner, Rohan and LehnerFeb 28 194777
Bernice SchinnerGardenTillman - JacobiDec 23 200518
Adam PagacBooksDoyle, Hodkiewicz and O'ConnellDec 04 196162
Earl RyanBeautyRau - O'HaraJan 08 196163
Greg BaileyHomeRau - O'HaraJan 02 196757
Anne PowlowskiMusicConnelly, Feest and HodkiewiczJan 26 195767
Abraham DooleyJeweleryTillman - JacobiOct 05 195668
Myron LemkeShoesFeest, Bogan and HerzogSep 27 197846
Dianna Gislason-LeschGamesCummerata - KuhlmanMay 29 196658
Reginald HagenesIndustrialRunte IncMay 19 195074
Shelia TurcotteMusicGoyette IncJul 22 195965
Carlton JenkinsSportsRunte IncJun 07 194381
Lance WiegandGroceryCummerata - KuhlmanJul 12 196658
Ruby GrahamSportsFeest, Bogan and HerzogMay 30 197054
Hattie CollierOutdoorsGoyette IncApr 14 195470
Viola RathMoviesRunte IncMar 24 197054
Roland HuelJeweleryDoyle, Hodkiewicz and O'ConnellApr 20 197351
Leticia WiegandKidsGoyette IncJan 13 195866
Jacqueline KulasBeautyFeest, Bogan and HerzogAug 30 196064
Cristina JaskolskiSportsFeest, Bogan and HerzogJan 25 196658
Felipe DaughertyMusicConnelly, Feest and HodkiewiczAug 12 196955
Timothy HeaneyKidsDoyle, Hodkiewicz and O'ConnellDec 05 200518
Alonzo KutchSportsTillman - JacobiMay 02 198242
Keith KlingSportsGoyette IncFeb 16 196163
Janice GoyetteSportsRunte IncMar 14 196361
Helen Kunze-MacGyverJeweleryDoyle, Hodkiewicz and O'ConnellFeb 11 200222
Barry JastGroceryRunte IncMay 09 197846
Ramiro CummingsSportsGoyette IncApr 09 196658
Antonio Little-BahringerGamesShanahan, Robel and BeierNov 21 198836
Samuel ZemlakElectronicsGoyette IncApr 28 196460
Doris EmardGamesRunte IncMay 04 200321
Olivia AbernathyOutdoorsRunte IncApr 30 196955
Justin KohlerHealthGoyette IncJan 11 198044
Scott OberbrunnerSportsGoyette IncJan 22 199727
Yolanda SpinkaMusicConnelly, Feest and HodkiewiczJan 19 198143
Brad Ullrich-OrnGamesFeest, Bogan and HerzogAug 08 195272
Gloria FisherHealthGoyette IncNov 20 199529
Sergio CristBooksGoldner, Rohan and LehnerMay 31 199529
Theresa SporerSportsGoyette IncMay 15 200321
Theodore WiegandGamesCummerata - KuhlmanMay 18 200024
Rudy RoweGroceryTillman - JacobiOct 01 196262
Kurt RaynorToysGoyette IncAug 20 195767
Ruth MedhurstHomeDoyle, Hodkiewicz and O'ConnellJan 09 194777
Tim AbernathyShoesDoyle, Hodkiewicz and O'ConnellOct 23 198440
Rebecca RunolfsdottirGroceryRunte IncJul 07 196460
Angel AufderharHealthRunte IncJun 22 195965
Javier BergstromMoviesCummerata - KuhlmanOct 20 199331
Leigh KlockoMusicRau - O'HaraJun 14 195569
Taylor RiceBeautyGoldner, Rohan and LehnerSep 10 194876
Cindy GoldnerShoesDoyle, Hodkiewicz and O'ConnellNov 30 197845
Shannon CristOutdoorsConnelly, Feest and HodkiewiczNov 12 199430
Sarah MaggioBooksGoyette IncNov 09 200024
Carlton Langosh-GloverBabyRunte IncDec 06 196657
Felicia RoobGamesDoyle, Hodkiewicz and O'ConnellDec 21 196855
Simon KuhicKidsGoldner, Rohan and LehnerMay 07 195866
Sharon DanielMusicRunte IncJul 05 199925
Erin BayerBooksTillman - JacobiJul 04 198242
Erika Powlowski-CorwinSportsConnelly, Feest and HodkiewiczOct 10 194975
Vicky PollichBooksCummerata - KuhlmanMay 22 198638
Felicia ZiemannIndustrialRunte IncDec 15 199132
Colleen CrooksAutomotiveRau - O'HaraJun 06 199826
Jimmy FisherKidsGoyette IncDec 10 194578
Lula ReichertGamesCummerata - KuhlmanMar 17 199529
Bethany SchinnerMoviesCummerata - KuhlmanNov 12 195173
Allen HackettHealthTillman - JacobiMay 07 198440
No records

The code for this example is as follows:

'use client';

import { ActionIcon, Button, Checkbox, MultiSelect, Stack, TextInput } from '@mantine/core';
import { DatePicker, type DatesRangeValue } from '@mantine/dates';
import { useDebouncedValue } from '@mantine/hooks';
import { IconSearch, IconX } from '@tabler/icons-react';
import { DataTable } from 'mantine-datatable';
import dayjs from 'dayjs';
import { useEffect, useMemo, useState } from 'react';
import { employees } from '~/data';

const initialRecords = employees.slice(0, 100);

export function SearchingAndFilteringExample() {
  const [records, setRecords] = useState(initialRecords);

  const departments = useMemo(() => {
    const departments = new Set(employees.map((e) => e.department.name));
    return [...departments];
  }, []);

  const [query, setQuery] = useState('');
  const [selectedDepartments, setSelectedDepartments] = useState<string[]>([]);
  const [birthdaySearchRange, setBirthdaySearchRange] = useState<DatesRangeValue>();
  const [seniors, setSeniors] = useState(false);
  const [debouncedQuery] = useDebouncedValue(query, 200);

  useEffect(() => {
    setRecords(
      initialRecords.filter(({ firstName, lastName, department, birthDate }) => {
        if (
          debouncedQuery !== '' &&
          !`${firstName} ${lastName}`.toLowerCase().includes(debouncedQuery.trim().toLowerCase())
        )
          return false;

        if (
          birthdaySearchRange &&
          birthdaySearchRange[0] &&
          birthdaySearchRange[1] &&
          (dayjs(birthdaySearchRange[0]).isAfter(birthDate, 'day') ||
            dayjs(birthdaySearchRange[1]).isBefore(birthDate, 'day'))
        )
          return false;

        if (selectedDepartments.length && !selectedDepartments.some((d) => d === department.name)) return false;

        if (seniors && dayjs().diff(birthDate, 'y') < 70) return false;

        return true;
      })
    );
  }, [debouncedQuery, birthdaySearchRange, selectedDepartments, seniors]);

  return (
    <DataTable
      height={300}
      withTableBorder
      withColumnBorders
      records={records}
      columns={[
        {
          accessor: 'name',
          render: ({ firstName, lastName }) => `${firstName} ${lastName}`,
          filter: (
            <TextInput
              label="Employees"
              description="Show employees whose names include the specified text"
              placeholder="Search employees..."
              leftSection={<IconSearch size={16} />}
              rightSection={
                <ActionIcon size="sm" variant="transparent" c="dimmed" onClick={() => setQuery('')}>
                  <IconX size={14} />
                </ActionIcon>
              }
              value={query}
              onChange={(e) => setQuery(e.currentTarget.value)}
            />
          ),
          filtering: query !== '',
        },
        {
          accessor: 'department.name',
          filter: (
            <MultiSelect
              label="Departments"
              description="Show all employees working at the selected departments"
              data={departments}
              value={selectedDepartments}
              placeholder="Search departments…"
              onChange={setSelectedDepartments}
              leftSection={<IconSearch size={16} />}
              comboboxProps={{ withinPortal: false }}
              clearable
              searchable
            />
          ),
          filtering: selectedDepartments.length > 0,
        },
        { accessor: 'department.company.name', title: 'Company' },
        {
          accessor: 'birthDate',
          textAlign: 'right',
          render: ({ birthDate }) => dayjs(birthDate).format('MMM DD YYYY'),
          filter: ({ close }) => (
            <Stack>
              <DatePicker
                maxDate={new Date()}
                type="range"
                value={birthdaySearchRange}
                onChange={setBirthdaySearchRange}
              />
              <Button
                disabled={!birthdaySearchRange}
                variant="light"
                onClick={() => {
                  setBirthdaySearchRange(undefined);
                  close();
                }}
              >
                Clear
              </Button>
            </Stack>
          ),
          filtering: Boolean(birthdaySearchRange),
        },
        {
          accessor: 'age',
          textAlign: 'right',
          render: ({ birthDate }) => dayjs().diff(birthDate, 'y'),
          filter: () => (
            <Checkbox
              label="Seniors"
              description="Show employees who are older than 70 years"
              checked={seniors}
              onChange={() => {
                setSeniors((current) => !current);
              }}
            />
          ),
        },
      ]}
    />
  );
}

Head over to the next example to discover more features.