Home/Filtering/Ranges & Two Conditions
Filtering

Ranges & Two Conditions

Filter one column by two conditions at once — between two numbers, inside a date span, or either of two values — joined by AND or OR. One setting on the column, and it works with your existing data source unchanged.

A range between two values

Salary between $70,000 and $100,000, and a review date inside the first quarter. Two conditions on one column, applied from code before the first request. Sort any column and the range still holds.

Name
Department
Salary
Review date
Employee 25
Engineering
$76,200
2024-01-25
Employee 26
Design
$77,500
2024-02-26
Employee 27
Sales
$78,800
2024-03-27
Employee 37
Engineering
$91,800
2024-01-09
Employee 38
Design
$93,100
2024-02-10
Employee 39
Sales
$94,400
2024-03-11
1–6 of 6

Both columns here open already ranged, applied from code before the first request. Press the funnel on either one to see the two conditions behind the 2 badge, and change them.

Dates: before and after are strict

A number column has ≥ and ≤, so an inclusive range says exactly what it means. A date column offers Equals, Before and After, and both comparisons are strict — Before 31 March excludes 31 March itself. So a whole quarter is written as the day either side of it: After 2023-12-31 AND Before 2024-04-01. Naming the quarter's own first and last day would silently drop the rows that fall on them.

The empty range

Nothing stops you asking for ≥ 120000 AND ≤ 90000. The grid applies it and the empty state appears — a range that excludes itself is a real answer, not a broken grid.

Either of two values

The same pair of conditions with the join switched to OR — departments reading like Sales or like Support. Open the funnel on Department and toggle AND to watch the grid empty.

Name
Department
Salary
Started
Employee 03
Sales
$47,600
2016
Employee 05
Support
$50,200
2018
Employee 09
Sales
$55,400
2022
Employee 11
Support
$58,000
2024
Employee 15
Sales
$63,200
2017
Employee 17
Support
$65,800
2019
Employee 21
Sales
$71,000
2023
Employee 23
Support
$73,600
2014
Employee 27
Sales
$78,800
2018
Employee 29
Support
$81,400
2020
Employee 33
Sales
$86,600
2024
Employee 35
Support
$89,200
2015
1–12 of 26

Two conditions do not have to be a range. Switch the join to OR and the same pair becomes "either of these" — here, departments reading like Sales or like Support. With AND this exact filter matches nothing, because no department is both.

Open the funnel on Department and press the AND toggle to watch the grid empty, then switch back. The join is part of the entry your server receives, so it has to honour it — see the joiner line in the previous example's server tab.

A range is two conditions on one column

A column filter holds one condition, so a number column gives you a floor or a ceiling and a date column gives you before or after. "Between 60k and 90k" and "started during Q1" need both ends at once — two conditions on the same column, joined by AND.

Set filter.multi: true and the column accepts a second condition. That is the whole setup: two conditions is what a column allows by default, so there is nothing else to configure.

How it reads

  • In filterMode: 'row' the first condition edits inline in the filter row, and a small chip (with a +1 badge) opens the second.
  • The popup shows one row per condition — pick an operator and a value — with an AND / OR toggle at the top.
  • The join applies to the whole column. You choose it once, not per condition.

One condition or two — the entry changes shape

A column with multi: true does not always send a stack. With one condition applied the entry is a plain { op, value }, exactly like a column without multi; the { kind: 'multi', join, conditions } shape appears from the second condition on. Both the popup and the inline editor collapse a lone condition back down.

So read the shape, not the column definition: check isMultiFilter(entry) rather than assuming every entry of a stackable column carries a list.

Client or server

The entry arrives on FetchParams.filters as plain, serialisable JSON. Pass the whole state to filterStatePredicate(filters, columns) for an in-memory source — the same helper resolves one-condition and two-condition entries — or translate it to SQL / Mongo so the filtering runs over the full dataset. The server/employees.ts tab is one honest translation.

Range filter API

PropertyTypeDefaultDescription
column.filter.multibooleanfalseLet the column hold more than one condition, joined by AND/OR. Required for a range — a range is two conditions on one column.
column.filter.maxConditionsnumber2How many conditions the column accepts. Two — a range — is the default and needs no configuration.
MultiFilterValue{ kind: 'multi', join: 'and' | 'or', conditions: FilterCondition[] }—The serialisable shape a ranged column contributes to params.filters — from the second condition on.
isMultiFilter(entry)entry is MultiFilterValue—Type guard for the two shapes a stackable column can send. One condition collapses to { op, value }.
filterStatePredicate(filters, columns)(row: T) => boolean—Library helper — resolves one-condition and two-condition entries into a single row predicate.
config.filterMode: 'row'FilterMode—First condition edits inline; a chip with a +N badge opens the rest.
[initialState]GridStateSnapshot—Applies a range before the first request — both examples here open filtered from code.