Skip to content

Filtering and Search

FilterVariants.svelte
<script lang="ts">
import { MaterialSvelteTable, type MRT_ColumnDef } from 'material-svelte-tanstack-table';
import { type Person, makeData, states } from '../data/makeData';
const columns: MRT_ColumnDef<Person>[] = [
{ accessorKey: 'firstName', header: 'First Name' }, // text (default)
{
accessorKey: 'state',
filterSelectOptions: states,
filterVariant: 'select',
header: 'State',
},
{ accessorKey: 'age', filterVariant: 'range', header: 'Age (range)', size: 200 },
{ accessorKey: 'salary', filterVariant: 'range-slider', header: 'Salary (slider)', size: 220 },
{
accessorFn: (row) => String(row.isActive),
filterVariant: 'checkbox',
header: 'Active',
id: 'isActive',
size: 140,
},
];
const data = makeData(80);
</script>
<MaterialSvelteTable
options={{
columns,
data,
enableColumnFilterModes: true,
enableFacetedValues: true,
initialState: { showColumnFilters: true },
}}
/>

Set filterVariant on a column to choose its input:

VariantInput
text (default)Text field
select, multi-selectDropdown. Give filterSelectOptions, or enable enableFacetedValues to build them from the data
rangeMin and max fields
range-sliderTwo-thumb slider
checkboxAny / true / false (compares the strings 'true' and 'false')
autocompleteText field with suggestions
date, datetime, time, and their -range formsNative date and time inputs

Date filters receive Date objects (HH:mm strings for time), so your column values should be Dates too.

Each column filters with a function (fuzzy by default). Let users switch with enableColumnFilterModes, limit the choices per column with columnFilterModeOptions, or set one with filterFn:

{ accessorKey: 'name', header: 'Name', filterFn: 'startsWith', columnFilterModeOptions: ['startsWith', 'contains'] }

Built in: fuzzy, contains, startsWith, endsWith, equals, notEquals, between, betweenInclusive, greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo, empty, notEmpty, plus TanStack’s.

Pass a function as a column’s filterFn:

{
accessorKey: 'name',
header: 'Name',
filterFn: (row, columnId, filterValue) =>
String(row.getValue(columnId)).toLowerCase().startsWith(String(filterValue).toLowerCase()),
}

To use a name instead (including as the globalFilterFn), register functions with the filterFns option. They are registered once, when the table is created:

options={{ columns, data, filterFns: { startsWithLetter }, globalFilterFn: 'startsWithLetter' }}

The search box is on by default, and fuzzy with ranked results. Useful options: enableGlobalFilter, globalFilterFn, enableGlobalFilterModes, enableGlobalFilterRankedResults, positionGlobalFilter and initialState.showGlobalFilter.

columnFilterDisplayMode is 'subheader' (a row under the headers, the default), 'popover' (opens from the column header) or 'custom' (you place the filters). A column’s Filter snippet replaces the built-in input.

Set manualFiltering: true and control columnFilters and globalFilter yourself. See Remote data.