Drill-Down
Drill-down lets users move between summary and detail inside the Pivot structure. In the current implementation there are two separate drill-down concepts: grouped row expansion and generated column collapse.
Source code
// src/components/pivot/PivotDrillDown.ts
import { defineCustomElements } from '@revolist/revogrid/loader';
defineCustomElements();
import NumberColumnType from '@revolist/revogrid-column-numeral';
import { currentTheme } from '../composables/useRandomData';
import type { DataType } from '@revolist/revogrid';
import { PIVOT_DRILLDOWN, PIVOT_DRILLDOWN_PLUGINS, PIVOT_DRILLDOWN_ROWS } from '../sys-data/pivot.drilldown';
export function load(parentSelector: string, rows: any[] | { isDark?: boolean } = PIVOT_DRILLDOWN_ROWS) {
const { isDark } = currentTheme();
// Ensure rows is an array with data, otherwise fallback to default data
const data = Array.isArray(rows) && rows.length > 0 ? rows : PIVOT_DRILLDOWN_ROWS;
const grid = document.createElement('revo-grid') as any;
grid.className = 'grow h-full w-full cell-border';
grid.range = true;
grid.resize = true;
grid.filter = true;
grid.colSize = 180;
grid.readonly = true;
grid.hideAttribution = true;
grid.theme = isDark() ? 'darkCompact' : 'compact';
grid.columnTypes = {
currency: new NumberColumnType('$0,0.00'),
};
grid.plugins = PIVOT_DRILLDOWN_PLUGINS;
grid.columns = [];
Object.assign(grid, {
pivot: { ...PIVOT_DRILLDOWN },
})
document.querySelector(parentSelector)?.appendChild(grid);
// Set source last after DOM attachment and config
grid.source = data;
return () => {
grid.remove();
};
}
<template>
<RevoGrid
class="grow h-full cell-border"
hide-attribution
range
resize
filter
:colSize="180"
:source="rows"
:pivot.prop="pivot"
:theme="isDark ? 'darkCompact' : 'compact'"
:plugins="plugins"
:column-types="columnTypes"
readonly
/>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
import RevoGrid from '@revolist/vue3-datagrid';
import NumberColumnType from '@revolist/revogrid-column-numeral';
import { currentThemeVue } from '../composables/useRandomData';
import { PIVOT_DRILLDOWN, PIVOT_DRILLDOWN_PLUGINS, PIVOT_DRILLDOWN_ROWS } from '../sys-data/pivot.drilldown';
const { isDark } = currentThemeVue();
const rows = ref(PIVOT_DRILLDOWN_ROWS);
const plugins = PIVOT_DRILLDOWN_PLUGINS;
const columnTypes = ref({
currency: new NumberColumnType('$0,0.00'),
});
const pivot = computed(() => ({
...PIVOT_DRILLDOWN,
}));
</script>
// src/components/pivot/PivotDrillDown.tsx
import { useMemo } from 'react';
import { RevoGrid } from '@revolist/react-datagrid';
import NumberColumnType from '@revolist/revogrid-column-numeral';
import { currentTheme } from '../composables/useRandomData';
import { PIVOT_DRILLDOWN, PIVOT_DRILLDOWN_PLUGINS, PIVOT_DRILLDOWN_ROWS } from '../sys-data/pivot.drilldown';
interface PivotDrillDownProps {
rows?: any[];
}
function PivotDrillDown({ rows }: PivotDrillDownProps) {
const { isDark } = currentTheme();
const data = useMemo(() => (Array.isArray(rows) && rows.length > 0 ? rows : PIVOT_DRILLDOWN_ROWS), [rows]);
const columnTypes = useMemo(
() => ({
currency: new NumberColumnType('$0,0.00'),
}),
[],
);
const pivot = useMemo(
() => ({ ...PIVOT_DRILLDOWN }),
[],
);
return (
<RevoGrid
className="grow h-full cell-border"
hideAttribution
range
resize
filter
colSize={180}
source={data}
columns={[]}
pivot={pivot}
theme={isDark() ? 'darkCompact' : 'compact'}
plugins={PIVOT_DRILLDOWN_PLUGINS}
columnTypes={columnTypes}
readonly
/>
);
}
export default PivotDrillDown;
import { Component, ViewEncapsulation, NO_ERRORS_SCHEMA } from '@angular/core';
import { RevoGrid } from '@revolist/angular-datagrid';
import NumberColumnType from '@revolist/revogrid-column-numeral';
import { currentTheme } from '../composables/useRandomData';
import { PIVOT_DRILLDOWN, PIVOT_DRILLDOWN_PLUGINS, PIVOT_DRILLDOWN_ROWS } from '../sys-data/pivot.drilldown';
@Component({
selector: 'pivot-drilldown-grid',
standalone: true,
imports: [RevoGrid],
template: `
<revo-grid
class="grow h-full cell-border"
[hideAttribution]="true"
[range]="true"
[resize]="true"
[filter]="true"
[colSize]="180"
[source]="rows"
[pivot]="pivot"
[theme]="theme"
[plugins]="plugins"
[columnTypes]="columnTypes"
[readonly]="true"
></revo-grid>
`,
encapsulation: ViewEncapsulation.None,
// Allows Angular demos to bind RevoGrid plugin props that are not wrapper inputs.
schemas: [NO_ERRORS_SCHEMA],
})
export class PivotDrillDownGridComponent {
rows = PIVOT_DRILLDOWN_ROWS;
theme = currentTheme().isDark() ? 'darkCompact' : 'compact';
columnTypes = {
currency: new NumberColumnType('$0,0.00'),
};
plugins = PIVOT_DRILLDOWN_PLUGINS;
pivot = { ...PIVOT_DRILLDOWN };
}
import type { GridPlugin } from '@revolist/revogrid';
import { PivotPlugin, type PivotConfig } from '@revolist/revogrid-enterprise';
import { AdvanceFilterPlugin, ColumnCollapsePlugin, RowOddPlugin, commonAggregators } from '@revolist/revogrid-pro';
import { PIVOT_TIME_RANGE_ROWS } from './pivot.shared';
export const PIVOT_DRILLDOWN_ROWS = PIVOT_TIME_RANGE_ROWS;
export const PIVOT_DRILLDOWN_PLUGINS: GridPlugin[] = [
PivotPlugin,
ColumnCollapsePlugin,
AdvanceFilterPlugin,
RowOddPlugin,
] as any[];
export const PIVOT_DRILLDOWN: PivotConfig = {
dimensions: [
{ prop: 'region', sortable: true },
{ prop: 'rep', sortable: true },
{ prop: 'year', sortable: true },
{ prop: 'quarter', sortable: true },
{
prop: 'sales',
name: 'Sales',
columnType: 'currency',
aggregators: {
sum: commonAggregators.sum,
},
},
],
rows: ['region', 'rep'],
columns: ['year', 'quarter'],
values: [{ prop: 'sales', aggregator: 'sum' }],
collapsed: true,
groupAggregations: true,
columnCollapse: {
collapsed: true,
aggregator: 'sum',
},
};
Row Drill-Down
Section titled “Row Drill-Down”Row drill-down is enabled when:
- the effective row hierarchy has more than one level
collapsedis a boolean orexpandedstate exists
const pivot: PivotConfig = { rows: ['region', 'rep'], values: [{ prop: 'sales', aggregator: 'sum' }], collapsed: true,};Behavior:
collapsed: truestarts grouped rows collapsedcollapsed: falsestarts grouped rows expandedexpandedstores per-group overrides using grouped path keys
PivotPlugin translates the Pivot row structure into RevoGrid grouping options, then emits pivot-config-update when users expand or collapse groups.
Grouped Row Aggregates
Section titled “Grouped Row Aggregates”Set groupAggregations: true to render aggregate values inside grouped Pivot rows.
const pivot: PivotConfig = { rows: ['region', 'rep'], columns: ['year'], values: [{ prop: 'sales', aggregator: 'sum' }], collapsed: true, groupAggregations: true,};Behavior:
- the grouped row still shows the expand/collapse UI and group label
- generated Pivot value columns show the aggregate for the current grouped branch
- nested groups aggregate only their own descendants
- collapsed groups still show their aggregate values
If you hide the grouped row field column (for example with hide-columns="region"), you can move the grouped label into the first visible row cell:
const pivot: PivotConfig = { rows: ['region', 'product'], columns: ['quarter'], values: [{ prop: 'revenue', aggregator: 'sum' }], collapsed: true, groupAggregations: true, groupLabelColumn: 'firstVisible',};groupLabelColumn modes:
'grouped'(default): keep label in the grouped field column'firstVisible': render label in the first currently visible row cell
Current limitation:
groupAggregationscurrently applies to the client-side Pivot path- server-side Pivot still renders grouped labels only unless backend-precomputed grouped aggregates are added
Column Drill-Down
Section titled “Column Drill-Down”Column drill-down is controlled by columnCollapse.
columnCollapse: { enabled: true, collapsed: false, aggregator: 'sum',}Behavior:
- generated Pivot column groups become collapsible
- collapsed groups render a placeholder header/cell
- placeholder cells use a collapsed-bucket aggregator, not a naive sum of visible child cells
Persisted state for generated groups lives in collapsedColumns.
Related Options
Section titled “Related Options”collapsed: row drill-down defaultexpanded: persisted row group expansion stategroupAggregations: render aggregate values inside grouped client-side Pivot rowsgroupLabelColumn: choose where grouped row labels render ('grouped'or'firstVisible')columnCollapse: enable and configure generated column collapsecollapsedColumns: persisted generated column collapse state
Placeholder Behavior
Section titled “Placeholder Behavior”When a column group is collapsed, Pivot can render:
- a default placeholder header based on the group name
- a custom placeholder header or cell template
- a custom collapsed aggregator, globally or per value field
This is useful when a collapsed analytical bucket should still show a meaningful aggregate instead of just hiding all child columns.
State Persistence
Section titled “State Persistence”PivotPlugin emits pivot-config-update as users interact with grouped rows or collapsible columns. That event is the right place to persist the current Pivot state if you want drill-down state to survive reloads.
Common Mistakes
Section titled “Common Mistakes”- Expecting row drill-down with only one row field.
- Expecting grouped rows to show metric values without enabling
groupAggregations. - Expecting
columnCollapseto work without generated column groups. - Treating
expandedas UI row indexes. It is persisted grouped state, not viewport position.
Continue with Sorting And Filtering or Plugin Lifecycle.