Docyrus

DataTableFilter

Typed filter builder with 7 data types, ~70 operators including relative dates, async option loading, faceted counts and a mobile step wizard.

iOSAndroid
Preview DataTableFilter on your device

Scan with Expo Go

Download Expo Go, then scan the QR code to preview native components.

The native port of the web data-table-filter engine. The DOM-free core (column model, operators, faceting, useDataTableFilters, createColumnConfigHelper) is copied from @docyrus/ui, so filter state (FiltersState) is interchangeable between platforms. The UI is re-skinned for phones: a Filter button opens an ActionSheet wizard (column → operator → value) and active filters show as pills — tap the operator or value of a pill to edit it, × to remove it.

Installation

pnpm dlx @docyrus/cli add @docyrus/rn-data-table-filter
Required Packages(2 packages)
pnpm add date-fns @react-native-community/datetimepicker

Usage

import { useState } from 'react';

import {
  DataTableFilter,
  createColumnConfigHelper,
  filterData,
  useDataTableFilters,
  type FiltersState
} from '@/components/docyrus-native/data-table-filter';

type Deal = { name: string; stage: string; amount: number; closeDate: Date; won: boolean };

const dtf = createColumnConfigHelper<Deal>();

const columnsConfig = [
  dtf.text().id('name').accessor(row => row.name).displayName('Name').icon('fal text').build(),
  dtf.option().id('stage').accessor(row => row.stage).displayName('Stage')
    .options([
      { label: 'Lead', value: 'lead', color: '#94a3b8' },
      { label: 'Won', value: 'won', color: '#22c55e' }
    ])
    .build(),
  dtf.number().id('amount').accessor(row => row.amount).displayName('Amount').build(),
  dtf.date().id('closeDate').accessor(row => row.closeDate).displayName('Close date').build()
];

export function DealsFilter({ deals }: { deals: Deal[] }) {
  const [filters, setFilters] = useState<FiltersState>([]);
  const { columns, actions, strategy } = useDataTableFilters({
    strategy: 'client',
    data: deals,
    columnsConfig,
    filters,
    onFiltersChange: setFilters
  });

  const visibleDeals = filterData(deals, columnsConfig, filters); // render these rows

  return (
    <>
      <DataTableFilter columns={columns} filters={filters} actions={actions} strategy={strategy} />
      <DealList deals={visibleDeals} />
    </>
  );
}

Server strategy (Docyrus items endpoint)

import { filtersToServerFilter } from '@/components/docyrus-native/data-table-filter';

const { columns, filters, actions } = useDataTableFilters({
  strategy: 'server',
  data: [],
  columnsConfig,
  calculateFacets: false,
  options: { stage: stageOptions },           // server strategy needs static options…
  faceted: { stage: stageCounts }              // …and (optionally) counts from the server
});

// Backend-safe payload: `like %x%`, `between`, `not between` → OR group, `contains any` for array columns,
// snake_case relative dates (`last_7_days`, `in_last_x_days` + N). Unsendable rules are dropped.
const params = { filters: filtersToServerFilter(filters, { columns: columnsConfig }) };

Async options (relation / user columns)

const ownerColumn = {
  ...dtf.option().id('owner').accessor(row => row.ownerId).displayName('Owner').build(),
  asyncOptions: {
    pageSize: 25,
    debounceMs: 300,
    load: async ({ search, page, pageSize, signal }) => {
      const res = await client.get('/v1/users', { params: { search, offset: page * pageSize, limit: pageSize }, signal });
      return { items: res.data.map(u => ({ value: u.id, label: `${u.firstname} ${u.lastname}`, imageUrl: u.photo })), hasMore: res.data.length === pageSize };
    }
  }
};

Loaded labels are HTML-entity decoded (&amp; → &), loads are aborted when the search changes or the sheet closes, and "Load more" fetches the next page.

API Reference

DataTableFilterProps

PropTypeDefaultDescription
columnsColumn<TData>[]—Required. Columns from useDataTableFilters().columns.
filtersFiltersState—Required. Current filter state (FilterModel[]).
actionsDataTableFilterActions—Required. Actions from useDataTableFilters().actions.
strategy'client' | 'server'—Required. client computes options / facets from data; server expects them from the host and filters nothing locally.
locale'en' | 'de' | 'fr' | 'nl' | 'zh_CN' | 'zh_TW''en'Bundled string catalog (web parity). An app UiTranslationProvider entry under ui.dataTableFilter.<key> wins.
combinator'and' | 'or''and'How the host combines filters — the value shown by the AND / OR toggle. useDataTableFilters and filterData default to AND.
onCombinatorChange(combinator: 'and' | 'or') => void—Shows an interactive AND / OR toggle when two or more filters are active.
classNamestring—Additional classes for the root view.

useDataTableFilters(options)

OptionTypeDefaultDescription
strategy'client' | 'server'—Required. Filtering strategy.
dataTData[]—Required. Rows used for option / facet / min-max derivation (pass [] for server-paged data).
columnsConfigColumnConfig<TData>[]—Required. Column definitions (hand-written or built with createColumnConfigHelper).
defaultFiltersFiltersState[]Initial state (uncontrolled).
filtersFiltersState—Controlled state — must be paired with onFiltersChange.
onFiltersChangeDispatch<SetStateAction<FiltersState>>—Controlled setter.
calculateFacetsbooleantrueCompute faceted counts from data. Disable when you supply faceted yourself.
optionsPartial<Record<optionColumnId, ColumnOption[]>>—Override option lists per option / multiOption column.
facetedPartial<Record<columnId, Map<string, number> | [number, number]>>—Faceted counts (option columns) or [min, max] (number columns).

Returns { columns, filters, actions, strategy }.

DataTableFilterActions

ActionSignatureDescription
addFilterValue(column, values) => voidAdd values to an option / multiOption filter (operator auto-switches is → is any of).
removeFilterValue(column, values) => voidRemove values; the filter is dropped when empty.
setFilterValue(column, values) => voidReplace the values of any filter type.
setFilterOperator(columnId, operator) => voidChange the operator.
removeFilter(columnId) => voidRemove one filter.
removeAllFilters() => voidClear everything.
upsertFilter(filter: FilterModel) => voidNative addition (optional). Insert / replace a whole filter in one step — how the wizard creates value-less filters (is empty, today).

ColumnConfig<TData>

FieldTypeDescription
idstringRequired. Column id (becomes FilterModel.columnId).
accessor(row: TData) => unknownRequired. Reads the cell value.
displayNamestringRequired. Label.
typeColumnDataTypeRequired. 'text' | 'number' | 'date' | 'option' | 'multiOption' | 'boolean' | 'uuid'.
iconstring | ReactNodeDocyrusIcon name ('fal user') or a node. Optional on native — a type default is used. (Web: LucideIcon, required.)
optionsColumnOption[]Static options (option / multiOption).
facetedOptionsMap<string, number>Server-supplied counts.
min / maxnumberNumber bounds (shown as input hints).
transformOptionFn(value) => ColumnOptionDerive options from raw values.
orderFn(a, b) => numberCustom option ordering.
asyncOptionsAsyncOptionsConfigPaged, debounced, abortable remote option loader.
trueLabel / falseLabelstringBoolean choice labels.
includeTimebooleanDate columns backed by a timestamp: datetime pickers, minute-precision comparison, day-range is.
groupstringSection header in the column picker (e.g. the relation a borrowed column comes through).
allowedOperatorsFilterOperators[type][]Restrict the operator list.
operatorNotestringOne line shown under a restricted operator list (already translated).

ColumnOption

FieldTypeDescription
labelstringRequired. Display label.
valuestringRequired. Stored value.
secondaryLabelstringDimmer second line.
iconstring | ReactElement | ElementTypeDocyrusIcon name, element or component.
imageUrlstringAvatar image.
colorstringColor dot (status / enum options).

AsyncOptionsConfig

FieldTypeDefaultDescription
load({ search, page, pageSize, signal }) => Promise<{ items: ColumnOption[]; hasMore?: boolean }>—Required. Page loader; forward signal to your HTTP client.
pageSizenumber25Items per page.
debounceMsnumber300Search debounce.

FilterModel

FieldTypeDescription
columnIdstringColumn id.
typeColumnDataTypeColumn data type.
operatorFilterOperators[type]Operator (see below).
valuesFilterValues<type>Values: strings (text / option / uuid), numbers (number, or [N] for X-days operators), Dates (date), booleans.

Operators

TypeOperators
textcontains, does not contain, is, is not, starts with, ends with, is empty, is not empty
numberis, is not, is less than, is less than or equal to, is greater than, is greater than or equal to, is between, is not between, is empty, is not empty
date (calendar)is, is not, is before, is on or after, is after, is on or before, is between, is not between, is empty, is not empty
date (relative)today, tomorrow, yesterday, last7/15/30/60/90/120Days, next7/15/30/60/90/120Days, lastWeek, thisWeek, nextWeek, lastMonth, thisMonth, nextMonth, beforeToday, afterToday, lastYear, thisYear, nextYear, first/second/third/fourthQuarter, last3Months, last6Months, and the N-day family xDaysAgo, xDaysLater, beforeLastXDays, inLastXDays, afterLastXDays, inNextXDays
optionis, is not, is any of, is none of, is empty, is not empty
multiOptioninclude, exclude, include any of, include all of, exclude if any of, exclude if all, is empty, is not empty
booleanis, is not, is empty, is not empty
uuidis, is not, is empty, is not empty (exact match only; a rule is only sent for a complete UUID)

Wizard behaviour

StepNative control
ColumnSearchable list sectioned by group; typing 2+ characters also lists matching option values across option columns, which toggle directly (web "quick search").
OperatorEvery operator of the type (date: Calendar / Relative sections), honouring allowedOperators + operatorNote. Value-less operators apply immediately.
Value — text / uuidText input (uuid shows an "incomplete UUID" hint).
Value — numberOne input, or Min / Max inputs for is between / is not between. Faceted min / max shown as placeholders.
Value — dateDateTimePicker (date or datetime by includeTime); From / To pickers (or DateTimeRangePicker with time) for ranges; preset chips (Today, Yesterday, Last 7 / 30 days, This week / month / year) switch is → is between; N input for X-days operators.
Value — option / multiOptionSearchable check list with faceted counts, color dots, icons, avatars; async columns load pages with "Load more". Several picks under is become is any of.
Value — booleanTrue / False rows (trueLabel / falseLabel) that apply on tap.

Utilities

ExportDescription
createColumnConfigHelper<TData>()Fluent builder: .text() .number() .date() .option() .multiOption() .uuid() → .id() .accessor() .displayName() .icon() .min() .max() .options() .transformOptionFn() .orderFn() .build().
filterData(data, columns, filters, { combinator?, now?, weekStartsOn? })Native addition. Client-side filtering applying every operator (relative dates resolved against local time).
evaluateFilter(cellValue, filter, options?)Native addition. Test one value against one FilterModel.
filtersToServerFilter(filters, { columns?, combinator?, getRuleOptions? })Native addition. Backend-safe Docyrus filter group; getRuleOptions(columnId) sets field, arrayColumn, includeTime.
filterToServerRule(filter, options?)One rule (or OR group) / null when unsendable.
resolveRelativeDateWindow(operator, days?, options?)Inclusive { from?, to? } window for a relative-date operator.
decodeHtmlEntities(text) / decodeOptionLabels(items)DOM-free entity decoding.
determineNewOperator, filterTypeOperatorDetails, isRelativeDateOperator, isXDaysRelativeOperator, DEFAULT_OPERATORSOperator metadata (web parity).
useFilterTranslation(locale)Translation function used by the component (ui.dataTableFilter.<key> → locale catalog → English).

i18n

Strings come from the bundled catalogs selected by locale (the web JSON files, verbatim). An app UiTranslationProvider overrides any of them under ui.dataTableFilter.<webKey> — e.g. ui.dataTableFilter.filter, ui.dataTableFilter.filters.date.today. Native-only strings: ui.dataTableFilter.apply (Apply), ui.dataTableFilter.back (Back), ui.dataTableFilter.removeFilter (Remove filter), ui.dataTableFilter.addFilter (Add filter), ui.dataTableFilter.or (or).

Data grid integration

The native DataGrid toolbar's filter sheet is built on this engine (web DataGridFilterMenu parity): cell variants map to filter types, FilterModels are written to TanStack columnFilters as { operator, value, endValue } (web grid operator names such as isBetween, includesAny, last7Days), and the grid's default filterFn applies every operator in memory, relative dates included. Array-backed variants (multi-select, tag-select, user-multi-select) use the array operators; duration columns are filtered in hours.

Migration from 0.x

BeforeNow
columns: FilterColumn[] ({ id, label, type, options })columns from useDataTableFilters({ columnsConfig }) (ColumnConfig: id, accessor, displayName, type, options).
filters: FilterItem[] ({ id, columnId, operator, value })filters: FiltersState ({ columnId, type, operator, values[] }).
onFiltersChangeactions (from the hook) — or pass filters + onFiltersChange to the hook.
strategy: 'and' | 'or'combinator + onCombinatorChange. strategy now means 'client' | 'server' (web).
type selectoption (single) / multiOption (multiple).
operators equals, contains, gt, lt, between, is_empty, is_not_emptyWeb operator names (is, contains, is greater than, is less than, is between, is empty, is not empty, …).
styleRemoved — use className.

Components

ComponentDescription
DataTableFilterFilter button, AND / OR toggle, active-filter pills and the wizard sheet.

Type Exports

TypeDescription
DataTableFilterPropsComponent props.
DataTableFilterCombinator'and' | 'or'.
DataTableFiltersOptionsuseDataTableFilters options.
DataTableFilterActionsFilter actions.
Column / ColumnConfig / ColumnConfigHelper / DataTableFilterConfigColumn model.
ColumnDataType / OptionBasedColumnDataTypeColumn data types.
ColumnOption / ColumnOptionExtendedOption model (extended adds selected, count).
AsyncOptionsConfigAsync option loader config.
FilterModel / FiltersState / FilterValues / FilterStrategyFilter state.
FilterOperators and TextFilterOperator, NumberFilterOperator, DateFilterOperator, OptionFilterOperator, MultiOptionFilterOperator, BooleanFilterOperator, UuidFilterOperatorOperator unions.
FilterIconstring | ReactNode.
Locale / FilterTranslateFni18n.
EvaluateFilterOptions / RelativeDateOptions / RelativeDateWindowClient filtering.
DocyrusFilterRule / DocyrusFilterGroup / ServerRuleOptions / ServerFilterOptionsServer serialization.

On this page