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 195073
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 196063
Felicia GleasonShoesDoyle, Hodkiewicz and O'ConnellMar 09 197747
Alfredo ZemlakGamesRunte IncNov 12 198835
Emily BartolettiAutomotiveRau - O'HaraJan 05 196856
Delores ReynoldsIndustrialRunte IncJun 04 200419
Louis SchambergerToolsCummerata - KuhlmanSep 07 199429
Beverly HellerBeautyRunte IncNov 29 200122
Eugene FeestKidsGoyette IncFeb 20 195470
Martin BahringerBeautyRau - O'HaraMay 26 194578
Ellis MillerElectronicsConnelly, Feest and HodkiewiczMay 24 195073
Gloria ColeHomeDoyle, Hodkiewicz and O'ConnellDec 09 199627
Linda WittingBabyDoyle, Hodkiewicz and O'ConnellMay 16 196558
Gregg KutchMoviesShanahan, Robel and BeierNov 28 198637
Mamie RaynorGroceryCummerata - KuhlmanNov 05 199231
Erick BruenElectronicsGoyette IncSep 26 195271
Faith LangworthClothingRunte IncNov 27 198340
Alicia LeannonSportsFeest, Bogan and HerzogDec 27 200518
Boyd MohrJeweleryGoyette IncJun 18 195172
Lindsey HeidenreichGamesShanahan, Robel and BeierJul 13 199726
Elsa MarvinBooksTillman - JacobiOct 07 198241
Debbie HagenesClothingRunte IncJan 24 196856
Lionel McCulloughKidsGoldner, Rohan and LehnerFeb 23 198638
Kim LebsackJeweleryCummerata - KuhlmanJun 11 197053
Rolando WeissnatHomeRau - O'HaraApr 25 195172
Jacqueline LeschGamesRunte IncJul 22 197845
Felix StokesKidsGoyette IncMar 21 198440
Renee TillmanIndustrialGoldner, Rohan and LehnerNov 24 195370
Richard WatsicaOutdoorsRunte IncJun 10 197152
Nathan WolfGamesGoldner, Rohan and LehnerJul 02 199825
Jonathan Keebler-CronaMusicGoyette IncOct 22 200221
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 195667
Myron LemkeShoesFeest, Bogan and HerzogSep 27 197845
Dianna Gislason-LeschGamesCummerata - KuhlmanMay 29 196657
Reginald HagenesIndustrialRunte IncMay 19 195073
Shelia TurcotteMusicGoyette IncJul 22 195964
Carlton JenkinsSportsRunte IncJun 07 194380
Lance WiegandGroceryCummerata - KuhlmanJul 12 196657
Ruby GrahamSportsFeest, Bogan and HerzogMay 30 197053
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 196063
Cristina JaskolskiSportsFeest, Bogan and HerzogJan 25 196658
Felipe DaughertyMusicConnelly, Feest and HodkiewiczAug 12 196954
Timothy HeaneyKidsDoyle, Hodkiewicz and O'ConnellDec 05 200518
Alonzo KutchSportsTillman - JacobiMay 02 198241
Keith KlingSportsGoyette IncFeb 16 196163
Janice GoyetteSportsRunte IncMar 14 196361
Helen Kunze-MacGyverJeweleryDoyle, Hodkiewicz and O'ConnellFeb 11 200222
Barry JastGroceryRunte IncMay 09 197845
Ramiro CummingsSportsGoyette IncApr 09 196658
Antonio Little-BahringerGamesShanahan, Robel and BeierNov 21 198835
Samuel ZemlakElectronicsGoyette IncApr 28 196459
Doris EmardGamesRunte IncMay 04 200320
Olivia AbernathyOutdoorsRunte IncApr 30 196954
Justin KohlerHealthGoyette IncJan 11 198044
Scott OberbrunnerSportsGoyette IncJan 22 199727
Yolanda SpinkaMusicConnelly, Feest and HodkiewiczJan 19 198143
Brad Ullrich-OrnGamesFeest, Bogan and HerzogAug 08 195271
Gloria FisherHealthGoyette IncNov 20 199528
Sergio CristBooksGoldner, Rohan and LehnerMay 31 199528
Theresa SporerSportsGoyette IncMay 15 200320
Theodore WiegandGamesCummerata - KuhlmanMay 18 200023
Rudy RoweGroceryTillman - JacobiOct 01 196261
Kurt RaynorToysGoyette IncAug 20 195766
Ruth MedhurstHomeDoyle, Hodkiewicz and O'ConnellJan 09 194777
Tim AbernathyShoesDoyle, Hodkiewicz and O'ConnellOct 23 198439
Rebecca RunolfsdottirGroceryRunte IncJul 07 196459
Angel AufderharHealthRunte IncJun 22 195964
Javier BergstromMoviesCummerata - KuhlmanOct 20 199330
Leigh KlockoMusicRau - O'HaraJun 14 195568
Taylor RiceBeautyGoldner, Rohan and LehnerSep 10 194875
Cindy GoldnerShoesDoyle, Hodkiewicz and O'ConnellNov 30 197845
Shannon CristOutdoorsConnelly, Feest and HodkiewiczNov 12 199429
Sarah MaggioBooksGoyette IncNov 09 200023
Carlton Langosh-GloverBabyRunte IncDec 06 196657
Felicia RoobGamesDoyle, Hodkiewicz and O'ConnellDec 21 196855
Simon KuhicKidsGoldner, Rohan and LehnerMay 07 195865
Sharon DanielMusicRunte IncJul 05 199924
Erin BayerBooksTillman - JacobiJul 04 198241
Erika Powlowski-CorwinSportsConnelly, Feest and HodkiewiczOct 10 194974
Vicky PollichBooksCummerata - KuhlmanMay 22 198637
Felicia ZiemannIndustrialRunte IncDec 15 199132
Colleen CrooksAutomotiveRau - O'HaraJun 06 199825
Jimmy FisherKidsGoyette IncDec 10 194578
Lula ReichertGamesCummerata - KuhlmanMar 17 199529
Bethany SchinnerMoviesCummerata - KuhlmanNov 12 195172
Allen HackettHealthTillman - JacobiMay 07 198439
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} />}
              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.