RevoGrid Filtering
Filtering lets users narrow the visible rows without changing the original source. RevoGrid keeps the full dataset available and hides non-matching physical row indexes through the trimming pipeline, so filtering works together with virtual scrolling, sorting, editing, and getVisibleSource().
Enable filtering
Turn on the built-in filter plugin with the grid-level filter prop:
const grid = document.querySelector('revo-grid');
grid.source = [
{ name: 'Steve', role: 'Admin', score: 92 },
{ name: 'Anna', role: 'Editor', score: 76 },
{ name: 'John', role: 'Viewer', score: 61 },
];
grid.columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'role', name: 'Role' },
{ prop: 'score', name: 'Score', filter: 'number' },
];
grid.filter = true;The grid-level filter value enables the plugin. The column-level filter value decides whether a column has a filter button and which filter family the panel should use.
RevoGrid filter propColumn filter option
Column filter options
Use filter on a column when you need to override the default behavior.
const columns = [
{ prop: 'name', name: 'Name' },
{ prop: 'internalId', name: 'Internal ID', filter: false },
{ prop: 'score', name: 'Score', filter: 'number' },
{ prop: 'status', name: 'Status', filter: ['string', 'selection'] },
];| Value | Use it for |
|---|---|
true | Enable the default filter family for the column. |
false | Hide the filter UI for the column. |
'string' | Text matching such as contains, starts with, and equals. |
'number' | Numeric comparisons such as greater than and less than. |
string[] | Multiple filter families, often used by Pro or custom filters. |
Built-in filter operations
String columns support notEmpty, empty, eq, notEq, begins, contains, and notContains.
Number columns support notEmpty, empty, eqN, neqN, gt, gte, lt, and lte.
Boolean and array columns support the blank operations notEmpty and empty.
In the filter panel, empty is labeled Is blank and notEmpty is labeled Is not blank. The operation ids have not changed, so existing saved filter state remains compatible. These ids are also the values used by include, localization, and event payloads.
Configure ColumnFilterConfig
Pass an object to grid.filter when you need controlled behavior instead of the default plugin setup.
grid.filter = {
include: ['contains', 'eq', 'notEmpty', 'gt', 'gte', 'lt', 'lte'],
disableDynamicFiltering: true,
closeFilterPanelOnOutsideClick: false,
allowDuplicateOperators: false,
};Important options:
| Option | Purpose |
|---|---|
blankSemantics | Defines which source values the blank operators match across the grid. |
collection | Restores single-filter state by column prop. |
multiFilterItems | Restores multiple filters per column, including and / or relations. |
include | Limits the operations shown in the dropdown. |
customFilters | Registers custom operations. |
filterProp | Uses a custom column property instead of filter to decide whether a column is filterable. |
localization | Replaces filter captions and operation names. |
disableDynamicFiltering | Applies changes only when the user confirms. |
closeFilterPanelOnOutsideClick | Controls whether outside clicks close the filter panel. |
allowDuplicateOperators | Allows the same operator to be selected more than once per column. Defaults to true; set to false to make visible operators mutually exclusive in the panel. |
When allowDuplicateOperators is false, the filter panel hides operators already used by the current column from the Add condition dropdown. Existing conditions remain editable, and programmatically supplied duplicate multiFilterItems are preserved.
ColumnFilterConfigFilterCollectionItemMultiFilterItem
Configure blank values
The Is blank and Is not blank operations preserve the original source value instead of converting all falsy values to the same representation. The default policy is:
| Source value | Blank by default |
|---|---|
null | Yes |
An own property whose value is undefined | Yes |
An empty string ('') | Yes |
| A missing own property | Yes |
A whitespace-only string such as ' ' | No |
An empty array ([]) | No |
false, 0, or NaN | No |
| Non-empty arrays and objects | No |
Set blankSemantics on the grid filter config to change this policy. Every field is optional:
grid.filter = {
blankSemantics: {
whitespaceOnlyString: true,
emptyArray: true,
null: true,
undefined: true,
emptyString: true,
missingProperty: true,
},
};A column can override individual fields without repeating the grid policy. Column settings are merged field-by-field over the grid settings and the defaults:
grid.columns = [
{
prop: 'tags',
name: 'Tags',
filter: 'array',
// Keep [] as a non-blank value for this column only.
blankSemantics: { emptyArray: false },
},
{
prop: 'active',
name: 'Active',
filter: 'boolean',
},
];Use isBlank for application-specific values. It runs after the configured rules and receives their result as fallbackResult:
grid.filter = {
blankSemantics: {
isBlank(value, context, fallbackResult) {
if (context.property === 'status' && value === 'N/A') {
return true;
}
return fallbackResult;
},
},
};The callback receives the unparsed source value plus a context containing model, column, property, sourceValue, parsedValue, hasOwnProperty, and the effective blankSemantics. Inherited properties count as missing because hasOwnProperty is false.
Blank checks always use sourceValue, even when the column has a cellParser. Other built-in and custom filter operations continue to receive parsedValue. Configuring blank semantics does not coerce values for typed comparisons, so number, string, boolean, and array operators keep their existing strict behavior.
Is not blank is the exact inverse of the resolved blank predicate, including the result returned by isBlank.
Customize filter names
Use localization.filterNames to replace the labels shown for built-in filter operations. For example, you can use shorter labels for the default Is blank and Is not blank operations:
import { filterNames } from '@revolist/revogrid';
grid.filter = {
localization: {
captions: {},
filterNames: {
...filterNames,
empty: 'Blank',
notEmpty: 'Not blank',
},
},
};Spreading filterNames keeps all other built-in labels unchanged and satisfies the complete FilterLocalization mapping expected by TypeScript. Override any other operation id in the same object, such as eq for Equal or contains for Contains. The ids remain empty and notEmpty for compatibility with saved filters, regardless of the labels you display.
Restore saved filters
Use collection for simple saved filters:
grid.filter = {
collection: {
role: { type: 'eq', value: 'Admin' },
score: { type: 'gte', value: 80 },
},
};Use multiFilterItems when a column needs several conditions:
grid.filter = {
multiFilterItems: {
score: [
{ id: 1, type: 'gte', value: 70 },
{ id: 2, type: 'lt', value: 95, relation: 'and' },
],
role: [
{ id: 3, type: 'eq', value: 'Admin' },
{ id: 4, type: 'eq', value: 'Editor', relation: 'or' },
],
},
};Filter parsed values
If a cell displays formatted text but filtering should use normalized data, add cellParser to the column or column type.
const columns = [
{
prop: 'total',
name: 'Total',
filter: 'number',
cellTemplate: (h, { model, prop }) =>
h('span', `$${Number(model[prop]).toLocaleString()}`),
cellParser: (model, column) => Number(model[column.prop] ?? 0),
},
];See Column Types and Formats and Custom Cell Formats for reusable parser patterns.
Create a custom filter
Register custom operations through customFilters. The columnFilterType must match the column's filter value.
const matchesPriority = (value, expected = 'critical') =>
String(value).toLowerCase() === String(expected).toLowerCase();
matchesPriority.extra = 'input';
grid.columns = [
{ prop: 'ticket', name: 'Ticket' },
{ prop: 'priority', name: 'Priority', filter: 'ticketPriority' },
];
grid.filter = {
include: ['isHighPriority'],
customFilters: {
isHighPriority: {
columnFilterType: 'ticketPriority',
name: 'High priority',
func: matchesPriority,
},
},
};The filter function receives the parsed cell value and the extra value from the filter panel. func.extra = 'input' asks the panel to render an input for that operation. The filter API also supports datepicker or a custom extra-field renderer for specialized UIs.
Event hooks
Filtering is event-driven. Use these hooks when your app needs to observe, rewrite, or replace filtering behavior.
grid.addEventListener('beforefilterapply', event => {
const { collection } = event.detail;
for (const prop of Object.keys(collection)) {
if (collection[prop].value === '') {
delete collection[prop];
}
}
});
grid.addEventListener('beforefiltertrimmed', event => {
console.log('Rows about to be hidden', event.detail.itemsToFilter);
});Useful events:
| Event | When to use it |
|---|---|
beforefilterapply | Inspect or modify the filter collection before rows are evaluated. |
beforefiltertrimmed | Inspect or replace the physical row indexes that will be hidden. |
beforetrimmed | Intercept trimming generally, including filtering-driven trimming. |
aftertrimmed | React after visible rows have changed. |
filterconfigchanged | Persist new filter config when the filter prop changes. |
For the full event table, see API: Events and API: RevoGrid. For the filtering event flow, see Event Patterns and Lifecycles.
When the backend must own the filtered dataset, intercept beforefilterapply, prevent local trimming, and reload source from your server. See Server-side data, pagination, sorting, and filtering.
Read filtered rows
After a filter is applied, use getVisibleSource() when the application needs the current visible dataset.
const visibleRows = await grid.getVisibleSource();
const visibleEmails = visibleRows.map(row => row.email);See Programmatic Control.
Pro filtering
The open-source filter plugin is a strong base: text and number operations, custom functions, localization, saved state, and event hooks are all available in the Community package. RevoGrid Pro builds on the same API and makes filtering feel closer to a full spreadsheet or back-office data product.
Import the Pro plugins and stylesheet, then add the plugins to the grid plugins list. AdvanceFilterPlugin adds selection, slider, quick-search, and date filter operations; FilterHeaderPlugin adds always-visible header inputs.
import {
AdvanceFilterPlugin,
FilterHeaderPlugin,
FIlTER_SELECTION,
FIlTER_SLIDER,
} from '@revolist/revogrid-pro';
import '@revolist/revogrid-pro/dist/revogrid-pro.css';
const plugins = [AdvanceFilterPlugin, FilterHeaderPlugin];
const columns = [
{ prop: 'city', name: 'City', filter: ['string', FIlTER_SELECTION] },
{ prop: 'status', name: 'Status', filter: [FIlTER_SELECTION] },
{ prop: 'createdAt', name: 'Created', filter: ['date'] },
{ prop: 'amount', name: 'Amount', filter: ['number', FIlTER_SLIDER] },
{ prop: 'owner', name: 'Owner', filter: ['input'] },
];
grid.plugins = plugins;
grid.columns = columns;
grid.filter = true;Advanced Selection Filtering
Selection filtering gives users a fast pick-list for repeated values such as status, city, category, owner, country, or product type. It is ideal for operational grids where users already know the value they want and should not have to type exact text into a generic input.
Advanced Slider Filtering
Slider filtering adds a range-based control for numeric columns. It works well for prices, quantities, ratings, scores, budgets, and other bounded numeric values where users want to narrow a dataset visually instead of entering gte and lte values manually.
Header Input Filtering
Header input filtering keeps filter inputs visible directly in the header row. This is useful for dense back-office screens where filtering is a constant workflow and users need to scan, type, adjust, and compare without opening a popup for every column.
Date Filter
Date filtering adds date-aware operations for temporal data such as schedules, orders, logs, audit records, deadlines, and activity history. Users can filter by exact dates, ranges, and common date windows without writing custom date parsing logic.
Multi-Filtering
Multi-filtering lets users combine several conditions per field with clearer and / or workflows. It is especially useful when a single column needs layered logic, for example "amount is greater than 100 and less than 500" or "status is open or pending".
These Pro filters are valuable when users live in the grid all day: they can narrow a large dataset from several angles, combine filters without leaving the table, and keep the interaction fast because the Pro features plug into RevoGrid's existing virtualized rendering and filter events.
Start with RevoGrid Pro features, or open the business demos that use Pro workflows: