Features guide
Everything below is available in the free @kanunilabs/pivotgrid-react
package unless a section is explicitly marked Enterprise. Each feature is
driven by props or per-field configuration — no imperative setup required.
Most features are configured on the PivotField objects you pass to
initialFields (or the controlled fields prop), or on the layout,
stateStoring, theme and toolbar props of BasePivotGrid.
Aggregation
Every measure (a field in the data area) declares a summaryType:
{ id: 'revenue', dataField: 'revenue', caption: 'Revenue', dataType: 'number',
area: 'data', summaryType: 'sum' }
Supported: sum, count, avg, min, max, distinct (distinct count) and
custom. All aggregation runs in the Web Worker, off the main thread.
Custom summaries
For bespoke rollups, provide calculateCustomSummary (start → calculate →
finalize), the same three-phase model used by classic pivot engines:
{ id: 'weightedAvg', dataField: 'price', caption: 'Weighted Avg', dataType: 'number',
area: 'data', summaryType: 'custom',
calculateCustomSummary: (o) => {
if (o.summaryProcess === 'start') o.totalValue = 0;
if (o.summaryProcess === 'calculate') o.totalValue += o.value ?? 0;
if (o.summaryProcess === 'finalize') o.totalValue = o.totalValue; // your math
} }
Summary display modes
Transform an aggregated value after it is computed with summaryDisplayMode:
{ id: 'revenue', dataField: 'revenue', caption: '% of Total', dataType: 'number',
area: 'data', summaryType: 'sum', summaryDisplayMode: 'percentOfTotal' }
| Mode | Shows each cell as… |
|---|---|
absolute | the raw aggregated value (default) |
percentOfTotal | % of the grand total |
percentOfRowTotal | % of its row total |
percentOfColumnTotal | % of its column total |
runningTotal | a cumulative running total |
difference | the difference from the previous value |
percentDifference | the % difference from the previous value |
Grouping
Group date and number fields with groupInterval:
{ id: 'orderDate', dataField: 'orderDate', caption: 'Month', dataType: 'date',
area: 'column', groupInterval: 'month' }
Date intervals: year, quarter, month, day. Numbers accept numeric
(bucketed) or a numeric bucket size, or custom.
Sorting & Top-N
Sort a field's own values, or sort a row/column dimension by a measure:
// Sort Regions by descending Revenue, keeping only the top 10 (rest → "Others").
{ id: 'region', dataField: 'region', caption: 'Region', dataType: 'string',
area: 'row', sortOrder: 'desc', sortBySummaryField: 'revenue',
topN: 10, topNShowOthers: true, topNOthersCaption: 'Other regions' }
sortBySummaryField targets a data field by id; topN + topNShowOthers
collapse the tail into a single "Others" row.
Filtering
Header filters are built in — click a row/column field header to include or exclude values. You can also seed filters declaratively:
{ id: 'country', dataField: 'country', caption: 'Country', dataType: 'string',
area: 'filter', filterType: 'include', filterValues: new Set(['USA', 'Germany']) }
The visual Prefilter builder (pre-aggregation, multi-condition) is an Enterprise feature — see Enterprise & licensing.
Conditional formatting
Style cells by value with expression rules. Each rule provides a formula
(value, cell) => boolean and a style applied when it returns true:
{ id: 'revenue', dataField: 'revenue', caption: 'Revenue', dataType: 'number',
area: 'data', summaryType: 'sum',
conditionalFormatting: [
{ type: 'expression', formula: (v) => v < 0, style: { color: '#dc2626', fontWeight: 600 } },
{ type: 'expression', formula: (v) => v > 100000, style: { backgroundColor: '#dcfce7' } },
] }
Rules are evaluated top-to-bottom and merged, so later rules win on conflicting
properties. style is a standard React CSSProperties object.
Totals & layout
Grand totals, subtotals and the row-header shape are controlled by the layout
prop (PivotLayoutState):
<BasePivotGrid
gridId="sales"
data={data}
initialFields={fields}
layout={{
showGrandTotals: 'both', // 'rows' | 'columns' | 'both' | 'none'
showSubTotals: 'rows',
totalsPosition: 'bottom', // 'top' | 'bottom'
rowHeaderLayout: 'tree', // 'tabular' (a column per field) | 'tree' (nested)
hideEmptySummaryCells: true, // drop empty rows/columns
dataFieldPosition: 'columns', // where measure captions live
}}
/>
Import
The footer's Import menu ingests external data without code. It reads
CSV / TSV / TXT, Excel (.xlsx, .xls, .xlsm, .xlsb), XML and
JSON, plus clipboard paste (delimited text) and drag-and-drop onto
the grid. Column types are inferred with locale-aware parsing (EU/US decimals,
dates, booleans, leading-zero IDs stay strings). Large files stream with a
progress bar and can be cancelled.
Receive imported rows via onImportData, and optionally show a preview +
column-mapping step first:
<BasePivotGrid
gridId="sales"
data={data}
initialFields={fields}
previewImport // show a preview/mapping step before applying
onImportData={(rows) => setData(rows)}
/>
Export
The footer's Export menu produces CSV, JSON (list / tree / full session
snapshot), XML, Print and Copy to clipboard (tab-separated) in the Community
build. Styled Excel (WYSIWYG Pivot View or flat List View) and PDF export are
Enterprise features — in Community they appear in the menu with an "Enterprise" badge,
and become active when you render EnterprisePivotGrid. Large exports stream off the main
thread and are cancellable, and CSV output is sanitized against formula injection.
Hook onExporting to observe or cancel an export:
<BasePivotGrid
gridId="sales" data={data} initialFields={fields}
onExporting={(e) => { if (!userAllowed) e.cancel = true; }}
/>
Saved views & state persistence
The footer's report menu lets users save, load and set a default named view
(fields + layout). Persist the whole grid state across reloads with
stateStoring:
<BasePivotGrid
gridId="sales" data={data} initialFields={fields}
stateStoring={{ enabled: true, type: 'localStorage', storageKey: 'sales-pivot' }}
/>
Use type: 'custom' with onSave/onLoad to persist to your own backend.
Theming & striping
The grid is themed entirely with CSS variables. Pass a theme object, or toggle
zebra striping with striped:
<BasePivotGrid
gridId="sales" data={data} initialFields={fields}
striped
theme={{ primary: '#0284c7', surfaceHeader: '#e0f2fe', border: '#bae6fd' }}
/>
Try the presets live in the Theming playground.
Localization & RTL
Twelve locales ship in the box; ar flips the layout to RTL automatically. See
the Quick start and the
Localization playground.
Performance
Aggregation runs in a Web Worker over columnar storage with a trie-based grouper,
so the UI stays responsive on 1M+ rows — try the
Big Data Performance playground (1K → 2M
rows). In bundlers that can't statically resolve the worker (e.g. Next.js), point
workerUrl at a served copy — see Next.js setup:
<BasePivotGrid workerUrl="/kanunilabs/pivot.worker.js" data={data} initialFields={fields} />
Toolbar customization
Show or hide individual footer controls with the toolbar prop:
<BasePivotGrid
gridId="sales" data={data} initialFields={fields}
toolbar={{ showExportButton: true, showImportFile: false, showCalculatedFields: false }}
/>
Looking for calculated fields, charts or drill-down? Those are in the Enterprise package. For every prop and type, see the API Reference.