Multi-condition filter (AND / OR)
Two conditions on ONE column, joined by AND or OR: a salary band (> 80k AND < 150k), age outliers (< 25 OR > 60). Open the funnel and click "+ Add condition", or drive it via api.setFilter({ operator, value, operator2, value2, join }).
A live, editable Svelte 5 data grid example. Open the interactive demo or read the documentation.
What this example shows
A single column can hold TWO conditions joined by AND or OR - a numeric band ("> 80k AND < 150k"), an either/or text match, an outlier filter ("< 25 OR > 60"). Open a column's funnel menu and click "+ Add condition", or drive it from the API with `setFilter(col, { operator, value, operator2, value2, join })`. The preset buttons below do exactly that.
Source code (178-multi-condition-filter.svelte)
<!-- Documented in: docs/help/filtering/filter-conditions.md -->
<script lang="ts">
/**
* 178. Multi-condition filter (AND / OR within one column)
* --------------------------------------------------------
* A single column can hold TWO conditions joined by AND or OR - a numeric
* band ("> 80k AND < 150k"), an either/or text match, an outlier filter
* ("< 25 OR > 60"). Open a column's funnel menu and click "+ Add condition",
* or drive it from the API with `setFilter(col, { operator, value,
* operator2, value2, join })`. The preset buttons below do exactly that.
*/
import {
SvGrid,
tableFeatures,
rowSortingFeature,
columnFilteringFeature,
type ColumnDef,
type SvGridApi,
} from '@svgrid/grid'
import { makePeople, type Person } from '../shared/seed'
const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
let rows = $state<Person[]>(makePeople(120))
let api = $state<SvGridApi<typeof features, Person> | null>(null)
let activePreset = $state<string>('band')
const columns: ColumnDef<typeof features, Person>[] = [
{ field: 'firstName', header: 'First name', width: 130 },
{ field: 'lastName', header: 'Last name', width: 130 },
{ field: 'department', header: 'Department', width: 150 },
{ field: 'age', header: 'Age', editorType: 'number', width: 100, align: 'right' },
{ field: 'salary', header: 'Salary', editorType: 'number', width: 150, align: 'right',
format: { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } } },
]
function salaryBand() {
activePreset = 'band'
api?.clearAllFilters()
// salary > 80,000 AND salary < 150,000 (a band)
api?.setFilter('salary', {
operator: 'greaterThan', value: '80000',
operator2: 'lessThan', value2: '150000', join: 'AND',
})
}
function ageOutliers() {
activePreset = 'outliers'
api?.clearAllFilters()
// age < 25 OR age > 60 (the two tails)
api?.setFilter('age', {
operator: 'lessThan', value: '25',
operator2: 'greaterThan', value2: '60', join: 'OR',
})
}
function clearAll() {
activePreset = 'none'
api?.clearAllFilters()
}
</script>
<section class="flex flex-col flex-1 min-h-0 gap-3">
<div class="flex flex-wrap items-center gap-2 shrink-0">
<button type="button" class="mc-btn" class:is-on={activePreset === 'band'} onclick={salaryBand}>
Salary 80k < x < 150k <span class="mc-join">AND</span>
</button>
<button type="button" class="mc-btn" class:is-on={activePreset === 'outliers'} onclick={ageOutliers}>
Age < 25 or > 60 <span class="mc-join mc-or">OR</span>
</button>
<button type="button" class="mc-btn" class:is-on={activePreset === 'none'} onclick={clearAll}>Clear</button>
<span class="text-xs" style="color: var(--sg-muted);">
…or open any column's <strong>funnel menu</strong> and click <em>+ Add condition</em>.
</span>
</div>
<p class="text-sm shrink-0" style="color: var(--sg-fg);">
Two conditions per column, joined by <code>AND</code> / <code>OR</code>.
Set via <code>api.setFilter(col, {'{'} operator, value, operator2, value2, join {'}'})</code>
or the column menu.
</p>
<div class="flex-1 min-h-0">
<SvGrid responsive={true}
data={rows}
columns={columns}
features={features}
filterMode="menu"
showColumnFilters={true}
showRowNumbers={true}
rowHeight={36}
containerHeight="100%"
fitColumns={true}
onApiReady={(next) => { api = next; salaryBand() }}
/>
</div>
</section>
<style>
.mc-btn {
display: inline-flex; align-items: center; gap: 0.4rem;
padding: 6px 12px; border-radius: 7px;
font-size: 12.5px; font-weight: 600;
color: var(--sg-fg); background: var(--sg-header-bg);
border: 1px solid var(--sg-border); cursor: pointer;
transition: border-color 120ms ease, background-color 120ms ease;
}
.mc-btn:hover { border-color: var(--sg-accent, #3b82f6); }
.mc-btn.is-on { border-color: var(--sg-accent, #3b82f6); background: color-mix(in oklab, var(--sg-accent, #3b82f6) 12%, transparent); }
.mc-join { font-size: 9px; font-weight: 800; letter-spacing: 0.05em; color: var(--sg-on-accent, #fff); background: var(--sg-accent, #3b82f6); border-radius: 4px; padding: 1px 5px; }
.mc-or { background: #8b5cf6; }
</style>Related documentation
More Filtering & Search examples
- Sort, filter, paginate - Three most-asked-for features wired together against ~5k rows.
- Excel-style filters - Per-column operator dropdown with active-filter chips and clear.
- Filter - between operator - Number + date columns expose a "Between" operator with From/To inputs. Drive it via the menu or imperatively with api.setFilter(id, { operator: "between", value, valueTo }).
- Highlighted search matches - External search input + a custom cell snippet that wraps matched substrings in <mark>. Filters the dataset AND visually flags hits.
- Find in grid (Ctrl+F) - Built-in find overlay with next / previous navigation. Scans every visible cell value; matches activate + scroll into view.