Selection Cascade Filter
Use filter.selection.cascadeOptions.enabled to make selection options context-aware.
In cascade mode, RevoGrid builds each column’s selection list from rows matching all active filters except filters for the current column. This keeps the current column reversible while still narrowing options in related columns.
Source code
grid.plugins = [AdvanceFilterPlugin];
grid.columns = [
{ prop: 'country', name: 'Country', filter: [FIlTER_SELECTION] },
{ prop: 'city', name: 'City', filter: [FIlTER_SELECTION] },
];
grid.filter = {
selection: {
cascadeOptions: {
enabled: true,
optionVisibility: 'hide',
},
},
};
return [
{ country: 'Germany', city: 'Berlin' },
{ country: 'Germany', city: 'Munich' },
{ country: 'France', city: 'Paris' },
{ country: 'France', city: 'Lyon' },
{ country: 'Poland', city: 'Warsaw' },
{ country: 'Poland', city: 'Krakow' },
];Use optionVisibility to control how values outside that context appear. A value is context-valid when at least one source row containing that value matches the active filters in the other columns.
| Mode | Options in the popup | Context-invalid options | Best suited for |
|---|---|---|---|
hide | Context-valid values only | Not rendered | Compact, spreadsheet-style cascading filters |
disable | Complete column domain | Visible but disabled | Showing users why a known value is currently unavailable |
show | Complete column domain | Visible and interactive | Workflows where users must edit future filter state across the complete domain |
hide is the default when cascading is enabled. The modes change option presentation and interaction only; they do not change how rows are filtered.
hide: show only relevant options
Section titled “hide: show only relevant options”cascadeOptions: { enabled: true, optionVisibility: 'hide',}Use hide for the most direct cascading experience. If the Country filter leaves only Germany, the City popup contains only Berlin and Munich. Paris, Lyon, Warsaw, and Krakow are omitted because they cannot affect the rows in the current country context.
The current column’s own filter is still ignored while its option list is built. For example, opening Country continues to show every country allowed by the other active columns, so users can reverse or broaden the Country selection.
disable: reveal unavailable options
Section titled “disable: reveal unavailable options”cascadeOptions: { enabled: true, optionVisibility: 'disable',}Use disable when users benefit from seeing the complete domain. With Germany active, Berlin and Munich remain interactive while cities from France and Poland remain visible with disabled checkboxes.
- Disabled options remain searchable and follow the configured sort order.
- Clicking a disabled option does not change the filter model.
- Select All and tree-selection cascades operate only on context-valid options.
- A custom
itemTemplatereceivesdisabled: truefor unavailable options.
This mode is useful when an unavailable value should be discoverable without allowing it to change the current cascade.
show: keep the complete domain interactive
Section titled “show: keep the complete domain interactive”cascadeOptions: { enabled: true, optionVisibility: 'show',}Use show when users must manage selections across the complete domain even when some values cannot currently affect visible rows. With Germany active, every city remains visible and interactive.
Changing Paris while Germany is active updates the stored City exclusion, but it does not immediately change the displayed rows because no German row has City = Paris. The change becomes observable if the Country filter is later broadened to include France. This makes show useful for preparing filter state ahead of an upstream change, but it is less compact than hide and offers less availability guidance than disable.
Preserved exclusions and header summaries
Section titled “Preserved exclusions and header summaries”Selection filters store excluded values. Every visibility mode preserves those exclusions when an option becomes context-invalid; cascading never silently prunes them.
For example, if Paris is excluded and Country is narrowed to Germany:
hidetemporarily removes Paris from the popup.disablekeeps Paris visible and disabled.showkeeps Paris visible and interactive.
When France becomes valid again, Paris returns with its previous unchecked state. The FilterHeader count and tooltip always summarize context-valid values, independently of popup mode. Consequently, disable and show can display more popup options than the denominator shown in the header badge.
Columns with cellParser build and compare their cascading options from parsed values, consistent with the Core filter parsed values behavior.
Set filter.selection.cascadeOptions.showDependencyNumbers to true to show 1, 2, and later badges on active header filter icons in the order those filters are applied. The badges are hidden by default; omit this option or set it to false to keep them hidden.
Source code
import { defineCustomElements } from '@revolist/revogrid/loader';
import { AdvanceFilterPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';
defineCustomElements();
const rows = [
{ country: 'Germany', city: 'Berlin', department: 'Sales' },
{ country: 'Germany', city: 'Munich', department: 'Engineering' },
{ country: 'France', city: 'Paris', department: 'Sales' },
{ country: 'France', city: 'Lyon', department: 'Support' },
{ country: 'Poland', city: 'Warsaw', department: 'Engineering' },
{ country: 'Poland', city: 'Krakow', department: 'Support' },
];
export function load(parentSelector: string) {
const grid = document.createElement('revo-grid');
grid.columns = [
{ name: 'Country', prop: 'country', filter: ['selection'] },
{ name: 'City', prop: 'city', filter: ['selection'] },
{ name: 'Department', prop: 'department', filter: ['selection'] },
];
grid.stretch = 'last';
grid.plugins = [AdvanceFilterPlugin, ColumnStretchPlugin];
grid.filter = {
multiFilterItems: {
department: [{ id: 0, type: 'selection', value: ['sales', 'support'], relation: 'and' }],
country: [{ id: 1, type: 'selection', value: ['france', 'poland'], relation: 'and' }],
},
selection: {
cascadeOptions: {
enabled: true,
optionVisibility: 'hide',
showDependencyNumbers: true,
},
},
};
grid.resize = true;
grid.theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
grid.hideAttribution = true;
document.querySelector(parentSelector)?.appendChild(grid);
grid.source = rows;
return () => grid.remove();
}
<template>
<RevoGrid
:theme="isDark ? 'darkCompact' : 'compact'"
:columns="columns"
:source="rows"
:plugins="plugins"
stretch="last"
:filter="filter"
hide-attribution
/>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import { AdvanceFilterPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';
import { currentThemeVue } from '../composables/useRandomData';
const { isDark } = currentThemeVue();
const columns = ref([
{ name: 'Country', prop: 'country', filter: ['selection'] },
{ name: 'City', prop: 'city', filter: ['selection'] },
{ name: 'Department', prop: 'department', filter: ['selection'] },
]);
const rows = ref([
{ country: 'Germany', city: 'Berlin', department: 'Sales' },
{ country: 'Germany', city: 'Munich', department: 'Engineering' },
{ country: 'France', city: 'Paris', department: 'Sales' },
{ country: 'France', city: 'Lyon', department: 'Support' },
{ country: 'Poland', city: 'Warsaw', department: 'Engineering' },
{ country: 'Poland', city: 'Krakow', department: 'Support' },
]);
const plugins = [AdvanceFilterPlugin, ColumnStretchPlugin];
const filter = computed(() => ({
multiFilterItems: {
department: [{ id: 0, type: 'selection', value: ['sales', 'support'], relation: 'and' }],
country: [{ id: 1, type: 'selection', value: ['france', 'poland'], relation: 'and' }],
},
selection: {
cascadeOptions: {
enabled: true,
optionVisibility: 'hide' as const,
showDependencyNumbers: true,
},
},
}));
</script>
import { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import { AdvanceFilterPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';
const rows = [
{ country: 'Germany', city: 'Berlin', department: 'Sales' },
{ country: 'Germany', city: 'Munich', department: 'Engineering' },
{ country: 'France', city: 'Paris', department: 'Sales' },
{ country: 'France', city: 'Lyon', department: 'Support' },
{ country: 'Poland', city: 'Warsaw', department: 'Engineering' },
{ country: 'Poland', city: 'Krakow', department: 'Support' },
];
export default function FilterSelectionCascade() {
const { isDark } = currentTheme();
const columns = useMemo(
() => [
{ name: 'Country', prop: 'country', filter: ['selection'] },
{ name: 'City', prop: 'city', filter: ['selection'] },
{ name: 'Department', prop: 'department', filter: ['selection'] },
],
[],
);
const plugins = useMemo(() => [AdvanceFilterPlugin, ColumnStretchPlugin], []);
const filter = useMemo(
() => ({
multiFilterItems: {
department: [{ id: 0, type: 'selection', value: ['sales', 'support'], relation: 'and' }],
country: [{ id: 1, type: 'selection', value: ['france', 'poland'], relation: 'and' }],
},
selection: {
cascadeOptions: {
enabled: true,
optionVisibility: 'hide' as const,
showDependencyNumbers: true,
},
},
}),
[],
);
return (
<RevoGrid
columns={columns}
source={rows}
plugins={plugins}
stretch="last"
filter={filter}
hide-attribution
theme={isDark() ? 'darkCompact' : 'compact'}
/>
);
}
import { Component, ViewEncapsulation } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import { AdvanceFilterPlugin, ColumnStretchPlugin } from '@revolist/revogrid-pro';
import { currentTheme } from '../composables/useRandomData';
@Component({
selector: 'filter-selection-cascade-grid',
standalone: true,
imports: [RevoGrid],
template: `
<revo-grid
[plugins]="plugins"
[columns]="columns"
[source]="source"
stretch="last"
[filter]="filter"
[hideAttribution]="true"
[theme]="theme"
style="min-height: 400px;"
></revo-grid>
`,
encapsulation: ViewEncapsulation.None,
})
export class FilterSelectionCascadeGridComponent {
theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
source = [
{ country: 'Germany', city: 'Berlin', department: 'Sales' },
{ country: 'Germany', city: 'Munich', department: 'Engineering' },
{ country: 'France', city: 'Paris', department: 'Sales' },
{ country: 'France', city: 'Lyon', department: 'Support' },
{ country: 'Poland', city: 'Warsaw', department: 'Engineering' },
{ country: 'Poland', city: 'Krakow', department: 'Support' },
];
columns = [
{ name: 'Country', prop: 'country', filter: ['selection'] },
{ name: 'City', prop: 'city', filter: ['selection'] },
{ name: 'Department', prop: 'department', filter: ['selection'] },
];
filter = {
multiFilterItems: {
department: [{ id: 0, type: 'selection', value: ['sales', 'support'], relation: 'and' }],
country: [{ id: 1, type: 'selection', value: ['france', 'poland'], relation: 'and' }],
},
selection: {
cascadeOptions: {
enabled: true,
optionVisibility: 'hide' as const,
showDependencyNumbers: true,
},
},
};
plugins = [AdvanceFilterPlugin, ColumnStretchPlugin];
}
Configuration
Section titled “Configuration”grid.filter = { multiFilterItems: { department: [{ id: 0, type: 'selection', value: ['sales', 'support'], relation: 'and' }], country: [{ id: 1, type: 'selection', value: ['france', 'poland'], relation: 'and' }], }, selection: { cascadeOptions: { enabled: true, optionVisibility: 'hide', showDependencyNumbers: true, }, },};Compatibility with custom getItems
Section titled “Compatibility with custom getItems”If selection.getItems is provided, that custom source is used as-is.
Cascade visibility modes are only applied to the built-in source loader; RevoGrid does not infer contextual availability for custom items.