Filter Badges
Filter badges give users an always-visible summary of the active filter model. AdvanceFilterPlugin owns the badge list, refreshes it when filters change, and routes remove and clear actions through the same filtering workflow as the popup and programmatic APIs.
Quick start
Section titled “Quick start”Register AdvanceFilterPlugin, then enable its plugin-owned badge list through the grid property:
import { AdvanceFilterPlugin } from '@revolist/revogrid-pro';import '@revolist/revogrid-pro/dist/revogrid-pro.css';
grid.plugins = [AdvanceFilterPlugin];grid.filter = true;grid.filterBadges = true;The plugin mounts the list in the grid’s header slot. Set grid.filterBadges = false to remove it. You can also assign an options object instead of true:
grid.filterBadges = { ariaLabel: 'Order filters', emptyLabel: 'All orders are visible', className: 'order-filter-list', badgeClassName: 'order-filter-badge',};The list starts with No active filters by default. Each active condition becomes its own badge; multiple conditions for one column remain separate and include their AND or OR relation in the default label.
Remove and clear filters
Section titled “Remove and clear filters”Every default badge has a remove button. Removing one condition preserves the remaining conditions and deletes the column entry when its last condition is removed. The badge list stays synchronized even when beforefilterapply is canceled for remote filtering.
The default renderer does not add a Clear all button. To clear filters programmatically, use the active plugin:
const filterPlugin = (await grid.getPlugins()).find( (plugin) => plugin instanceof AdvanceFilterPlugin,) as AdvanceFilterPlugin | undefined;
await filterPlugin?.clearFiltering();A complete custom renderer also receives a clear() action. Its items expose individual remove() actions:
grid.filterBadges = { render: ({ items, clear }) => { const region = document.createElement('section'); region.setAttribute('aria-label', 'Active filters');
const list = document.createElement('div'); list.setAttribute('role', 'list');
for (const item of items) { const entry = document.createElement('div'); entry.setAttribute('role', 'listitem');
const removeButton = document.createElement('button'); removeButton.type = 'button'; removeButton.textContent = `${item.label} — remove`; removeButton.addEventListener('click', () => void item.remove());
entry.append(removeButton); list.append(entry); }
const clearButton = document.createElement('button'); clearButton.type = 'button'; clearButton.textContent = 'Clear all filters'; clearButton.disabled = items.length === 0; clearButton.addEventListener('click', () => void clear());
region.append(list, clearButton); return region; },};Default labels and details
Section titled “Default labels and details”Default labels use the column name, localized operator name, and a compact value summary. Selection filters report the number of excluded values, ranges show their endpoints, and structured filter types can supply their own compact summaries.
When a condition has a longer explanation, the badge includes an info button. It toggles a plain-text tooltip, exposes aria-controls and aria-expanded, and closes on Escape. Unknown object values are summarized without exposing transport JSON.
Use formatLabel and formatDetails when the default badge structure is correct but its text is application-specific:
grid.filterBadges = { formatLabel: ({ column, prop, operatorName, filter, index }) => { const name = column?.name ?? String(prop); const relation = index ? `${filter.relation?.toUpperCase() ?? 'AND'} ` : ''; return `${name}: ${relation}${operatorName}`; }, formatDetails: ({ filter }) => `Applied value: ${String(filter.value ?? 'none')}`, removeAriaLabel: (item) => `Remove condition ${item.label}`, detailsAriaLabel: (item) => `Explain condition ${item.label}`,};Both format callbacks receive prop, filter, the condition index, the matching column when available, and operatorName. formatDetails should return an empty string to suppress the info control; returning undefined allows the built-in details to be used.
Accessibility and styling options
Section titled “Accessibility and styling options”The default renderer provides these semantics:
- The root has
aria-label="Active filters"andaria-live="polite". - An empty list uses
role="status"; an active list usesrole="list"withrole="listitem"badges. - Remove buttons default to
Remove {label} filter. - Details buttons default to
Show details for {label}.
Customize the root label with ariaLabel, the empty message with emptyLabel, and the two button labels with removeAriaLabel and detailsAriaLabel. Add classes without replacing the built-in styles through className, badgeClassName, removeButtonClassName, and emptyClassName.
The default shell owns these semantics. A complete render callback replaces the list and releases its managed role, so your renderer must provide suitable roles, labels, focus behavior, and controls.
Customize badge content
Section titled “Customize badge content”renderBadge replaces only the label content inside the default badge shell. The plugin still renders the list semantics, optional details control, and remove button:
grid.filterBadges = { renderBadge: ({ item }) => { const strong = document.createElement('strong'); strong.textContent = item.label; return strong; },};Use renderEmpty to replace only the content inside the default empty-state element:
grid.filterBadges = { renderEmpty: () => { const message = document.createElement('span'); message.textContent = 'No filters — showing every row'; return message; },};renderBadge, renderEmpty, and render can return DOM nodes, a DocumentFragment, numbers, or nested arrays of supported values. Returned strings are always inserted as text, never parsed as HTML:
grid.filterBadges = { renderBadge: ({ item }) => [item.label, '<em>text, not markup</em>'],};To render HTML or Markdown, sanitize it with your application’s renderer and return the resulting DOM nodes or fragment. RevoGrid does not parse renderer strings as markup.
Observe badge-model changes
Section titled “Observe badge-model changes”onChange runs after each badge refresh, including the initial render. It receives the current read-only badge items:
grid.filterBadges = { onChange: (items) => { activeFilterCount.textContent = String(items.length); },};Each item contains a render key, label, optional details, source filter context, and remove() action. Treat the array and items as read-only; update filtering through the provided actions or the filter plugin APIs.
Options reference
Section titled “Options reference”| Option | Purpose |
|---|---|
className | Adds classes to the plugin-owned root. |
badgeClassName | Adds classes to each default badge. |
removeButtonClassName | Adds classes to each default remove button. |
emptyClassName | Adds classes to the default empty-state element. |
ariaLabel | Labels the live badge region. |
emptyLabel | Replaces the default No active filters message. |
removeAriaLabel | Produces the accessible label for a remove button. |
detailsAriaLabel | Produces the accessible label for a details button. |
formatLabel | Produces the badge’s plain-text label. |
formatDetails | Produces the complete plain-text details explanation. |
renderBadge | Replaces label content while retaining the default shell and actions. |
renderEmpty | Replaces content inside the default empty-state shell. |
render | Replaces the complete list; use item.remove() and clear() to retain behavior. |
onChange | Observes the current badge items after every refresh. |
Common mistakes
Section titled “Common mistakes”- Registering
filterBadgeswithoutAdvanceFilterPlugin. The property is implemented and managed by that plugin. - Expecting a string returned by a render callback to become HTML. Strings are intentionally text-safe; return trusted DOM nodes for rich content.
- Using full
renderwithout wiringitem.remove()andclear(). Replacing the complete UI also makes your application responsible for its controls. - Assuming the default renderer includes a clear-all action. It provides per-condition removal; add a custom control or call
clearFiltering(). - Omitting accessibility from a full renderer. Unlike
renderBadgeandrenderEmpty, fullrenderreplaces the list structure and its managed role. - Mutating the items received by
onChange. Use the filter APIs so the grid, remote filtering, and badges stay synchronized. - Treating badge actions as an editor for every canonical AST. Badges can summarize a grouped AST that cannot project to
MultiFilterItem, but per-condition removal is available only for projectable state; update that tree withsetFilterAst()or clear it withclearFiltering().