Capítulo 35 de 54
Column filtering applies per-column, named filterFns against ColumnFiltersState (an array, so multiple column filters compose); v9 ships 18 built-in filter functions and a constructFilterFn helper for building/deriving your own from a value comparator plus optional value-normalization hooks.
columnFilteringFeature + (for client-side) filteredRowModel: createFilteredRowModel() + only the filterFns you actually use (registering the full built-in registry ships every built-in implementation). For server-side, set manualFiltering: true and skip the row model — data is assumed pre-filtered.ColumnFiltersState = Array<{ id: string; value: unknown }> — an array, not a map, so several columns can be filtered simultaneously.table.state.columnFilters (reactive) or table.atoms.columnFilters.get() (snapshot, no subscription). Ownership: external atom via atoms.columnFilters (v9-recommended, e.g. feeding a server query key) or classic state.columnFilters + onColumnFiltersChange; or initialState.columnFilters alone if you never need it externally — never both initialState and state for the same slice.filterFns, grouped by shape: string — includesString/includesStringSensitive, startsWith, endsWith, equalsString/equalsStringSensitive; general equality — equals (===), weakEquals (==); emptiness — empty/notEmpty (filter value is an on/off flag, tests nullish-or-whitespace); array-valued — arrIncludes (row value includes any filter value, works on arrays or strings), arrIncludesAll, arrIncludesSome, arrHas (scalar row value equals any filter value); ranges — inNumberRange (inclusive, endpoints auto-normalized/swapped), inDateRange (inclusive, accepts Date/timestamp/date-string, blank endpoints open-ended), between (exclusive), betweenInclusive (inclusive, both range-style with open-ended blanks).constructFilterFn({ filter, resolveFilterValue?, resolveDataValue?, autoRemove? }): filter(dataValue, filterValue) is the actual comparator; resolveFilterValue normalizes the filter input once per filter application (not per row — the right place for expensive prep); resolveDataValue normalizes each row's value before comparison (honored by every built-in filter, since they're all built with constructFilterFn); autoRemove(value) returns true when that filter value should be dropped from state entirely (authoritative when provided — an undefined value always clears regardless). A function built this way carries its definition, so you can spread and override an existing one to derive a variant (e.g. a diacritic-insensitive version of includesString that only overrides the two resolve* hooks, reusing the original comparator/autoRemove).filterFn (inline or registered): (row, columnId, filterValue, addMeta?) => boolean — return true to keep the row.filterFn: 'myCustomFilterFn') only type-check if registered in the filterFns slot on tableFeatures; skip registration entirely by passing the function directly to the column's filterFn option instead.enableColumnFilter: false per-column, enableColumnFilters: false table-wide, or enableFilters: false to kill both column and global filtering at once.filterFromLeafRows: true inverts this — filtering runs leaf-up, so a parent survives if any descendant matches. maxLeafRowFilterDepth: 0 restricts filtering to root rows only, leaving all sub-rows unfiltered (useful to keep a parent's children intact once the parent itself passes).const startsWithFilterFn = constructFilterFn({
filter: (dataValue, filterValue) => Boolean(dataValue?.startsWith(filterValue)),
resolveFilterValue: (v) => String(v).toLowerCase().trim(),
resolveDataValue: (v) => String(v ?? '').toLowerCase(),
autoRemove: (v) => !v,
})
// deriving a diacritic-insensitive variant by overriding only the resolvers
const normalize = (v: unknown) => String(v ?? '').toLowerCase().normalize('NFD').replace(/\p{Diacritic}/gu, '')
const includesStringIgnoreDiacritics = constructFilterFn({
...filterFn_includesString,
resolveFilterValue: normalize,
resolveDataValue: normalize,
})
constructFilterFn-built function and overriding just the normalization hooks.resolveFilterValue runs once per filter, not per row — put expensive input normalization there, not in filter itself.filterFromLeafRows/maxLeafRowFilterDepth deliberately — the default (filter-from-root) silently drops matching children under a non-matching parent.constructFilterFn-style custom filter built around ranking metadata.filterMeta, for filter functions that need to hand data to a paired sort function.