Filtering
Quick search, per-column filters, faceted isAnyOf and isNoneOf, the header filter, and isBetween ranges.
The toolbar's search and filter surface: quick-search with match navigation, per-column filter menus, and click-to-sort headers (asc → desc → clear. Shift-click appends a secondary sort). The operator set adapts to the cell type. That's where faceted and range filtering live.
Click a header to sort (click again to reverse, a third click clears it); shift-click another header to add it as a secondary sort. Use Filter in the toolbar for per-column filters.
pnpm dlx shadcn@latest add @gridcn/data-grid-sorting-filtering-demo
What's in the demo
DataGridSearch: quick-search. It highlights and navigates matches, and never narrowsviewIndexDataGridFilterMenu: one filter perfilterable: truecolumn, joined with AND/ORheaderClickBehavior="sort": click cycles asc → desc → clear
Faceted (multi-value) filters
On select columns the filter menu offers isAnyOf: pick any number of options.choices
and a row matches if its value is in the list. That is the faceted-filter shape: one filter
per column, multiple values each. isNoneOf is the opposite: a row matches if its value is not in
the list. text, number, and date columns offer both operators too.
Header filter
NewThe header filter puts a searchable list of the column's values in each column header. The user
checks the values to keep, and the grid stores the shorter of the checked and unchecked lists as
isAnyOf or isNoneOf. See the toolbar add-on.
Range filters
number and date columns get isBetween: an inclusive [min, max] tuple where either
bound can be empty for an open-ended range (["", "10"] = "≤ 10"). Dates work because the
date type stores ISO strings, which compare lexicographically.
Per-option counts (DIY)
The filter menu does not render live counts per choice. If you want them, compute them app-side from your own data and render them next to your choice UI. The grid only owns the match logic:
// app-side facet counts for a select column
const counts = useMemo(() => {
const map = new Map<string, number>();
for (const row of data) {
const value = row.role;
map.set(value, (map.get(value) ?? 0) + 1);
}
return map;
}, [data]);Related
- Sorting, filtering & search guide: the full add-on reference
- URL state: filters serialize into shareable URLs via
isAnyOf/isNoneOf/isBetween