Documentation

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' }
ModeShows each cell as…
absolutethe raw aggregated value (default)
percentOfTotal% of the grand total
percentOfRowTotal% of its row total
percentOfColumnTotal% of its column total
runningTotala cumulative running total
differencethe difference from the previous value
percentDifferencethe % 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.