You have flat sales rows: region, product, quarter, revenue. Stakeholders want a matrix—regions down the left, quarters across the top, summed revenue in every cell. That reshape is a React pivot table: row dimensions, column dimensions, and aggregated measures in a data grid.
In many libraries, pivot mode is locked behind an Enterprise license. AG Grid's interactive Pivot Panel is powerful—and priced accordingly. Simple Table ships declarative matrix pivot plus an in-table Pivot Panel (enablePivotPanel) that drives the same config API.
This React pivot table tutorial covers how pivot tables work in a JavaScript data grid, when to choose pivot vs row grouping, and how to configure Simple Table for aggregations, nested dimensions, totals, and runtime updates.
What Is a React Pivot Table?
A pivot table in React turns fact rows into a cross-tab matrix:
- • Rows — fields that stay on the left (e.g. region, product)
- • Columns — fields whose distinct values become dynamic headers (e.g. quarter, channel)
- • Values — measures aggregated into each cell (sum, average, count, min, max, or custom)
Flat input like { region: 'West', quarter: 'Q1', sales: 1200 } becomes a West row with a Q1 sales cell. Multiple source rows that share the same dimensions collapse into one aggregated cell—classic spreadsheet-style pivoting inside your React data grid.
Common use cases: revenue by region × quarter, units by product × channel, tickets by team × status, and any analytics dashboard where columns must be generated from data—not hardcoded in your header config.
Pivot Table vs Row Grouping in React
Use a matrix pivot table when…
- • You need dimensions as columns (quarters across the top)
- • Cell values are aggregates, not detail rows
- • Column headers should be generated from distinct field values
- • You want row/column/grand totals in the matrix
Use row grouping when…
- • You still need to see individual fact rows
- • Hierarchy is expand/collapse down the left, not a cross-tab
- • Columns stay fixed; you're organizing rows, not reshaping them
- • See the row grouping docs and tree data guide
While pivot is active in Simple Table, consumer rowGrouping is ignored. Multi-level pivot.rows stay flat — one grid row per combination (e.g. region × product).
How to Build a React Pivot Table (Declarative Config)
Simple Table's matrix engine is declarative. Pass flat rows, a field catalog in columns, and a pivot config. End users can also arrange fields with enablePivotPanel, or your app can drive TableAPI.setPivot.
That gives teams a practical AG Grid pivot alternative: matrix pivoting and an in-table Pivot Panel without AG Grid Enterprise pricing.
1import { SimpleTable } from "@simple-table/react";2import type { ReactColumnDef, Row } from "@simple-table/react";3import "@simple-table/react/styles.css";45const headers: ReactColumnDef[] = [6 { accessor: "region", label: "Region", width: 110, type: "string" },7 { accessor: "quarter", label: "Quarter", width: 80, type: "string" },8 { accessor: "sales", label: "Sales", width: 100, type: "number", align: "right" },9];1011const rows: Row[] = [12 { id: "r1", region: "West", quarter: "Q1", sales: 1200 },13 { id: "r2", region: "West", quarter: "Q2", sales: 1500 },14 { id: "r3", region: "East", quarter: "Q1", sales: 900 },15 { id: "r4", region: "East", quarter: "Q2", sales: 1100 },16];1718export default function RevenuePivot() {19 return (20 <SimpleTable21 columns={headers}22 rows={rows}23 // Same shape as the docs / analytics "Region × Quarter" preset24 pivot={{25 rows: ["region"],26 columns: ["quarter"],27 values: [{ accessor: "sales", aggregation: { type: "sum" } }],28 }}29 columnResizing30 height="400px"31 />32 );33}
When pivot is active, the grid does not show the field catalog as columns. It shows generated row-dimension columns plus dynamic value columns from the pivot result. Full prop reference lives in the pivot table docs.
Nested Pivot Dimensions, Multiple Measures, and Totals
Multiple row fields
One or many row fields stay tabular: each distinct combination is its own grid row (docs/analytics "Region × Product" style presets). No expand/collapse hierarchy:
1<SimpleTable2 columns={headers}3 rows={rows}4 pivot={{5 rows: ["region", "product"],6 columns: ["quarter"],7 values: [{ accessor: "sales", aggregation: { type: "sum" } }],8 }}9 height="400px"10/>
Nested column groups
Multiple column fields produce nested headers (year → quarter):
1// Docs / analytics preset: "Category × Year → Quarter"2pivot={{3 rows: ["category"],4 columns: ["year", "quarter"],5 values: [{ accessor: "sales", aggregation: { type: "sum" } }],6}}
Multiple measures and totals
Add more value fields for side-by-side metrics—same pattern as the docs/analytics "Channel × Quarter" preset. Aggregation types match Simple Table's aggregate functions. Totals (showRowTotals, showColumnTotals, showGrandTotal) default to true:
1pivot={{2 rows: ["channel"],3 columns: ["quarter"],4 values: [5 { accessor: "sales", aggregation: { type: "sum" }, label: "Sales" },6 { accessor: "units", aggregation: { type: "sum" }, label: "Units" },7 ],8}}
Value-only layout (no column dimensions)
Pass an empty columns array to group and aggregate without generating a matrix of dynamic headers—same idea as the docs "Values only" preset:
1pivot={{2 rows: ["region", "category"],3 columns: [],4 values: [5 { accessor: "sales", aggregation: { type: "sum" } },6 { accessor: "cost", aggregation: { type: "sum" } },7 ],8}}
Update a React Pivot Table at Runtime (TableAPI)
The analytics demo and docs pivot demo swap presets by updating the controlled pivot prop (not setPivot):
1import { useState } from "react";2import { SimpleTable } from "@simple-table/react";3import type { PivotConfig } from "@simple-table/react";45const presets: { id: string; label: string; pivot: PivotConfig | null }[] = [6 { id: "source", label: "Source data", pivot: null },7 {8 id: "region-quarter",9 label: "Region × Quarter",10 pivot: {11 rows: ["region"],12 columns: ["quarter"],13 values: [{ accessor: "sales", aggregation: { type: "sum" } }],14 },15 },16 {17 id: "multi-rows",18 label: "Region × Product",19 pivot: {20 rows: ["region", "product"],21 columns: ["quarter"],22 values: [{ accessor: "sales", aggregation: { type: "sum" } }],23 },24 },25];2627export default function AnalyticsPivot() {28 const [activeId, setActiveId] = useState(presets[0].id);29 const active = presets.find((p) => p.id === activeId) ?? presets[0];3031 return (32 <>33 {presets.map((preset) => (34 <button key={preset.id} type="button" onClick={() => setActiveId(preset.id)}>35 {preset.label}36 </button>37 ))}38 <SimpleTable39 columns={headers}40 rows={rows}41 pivot={active.pivot}42 height="480px"43 />44 </>45 );46}
Prefer imperative control? TableAPI.setPivot (documented on the pivot docs) updates the same config without remounting:
1const tableRef = useRef<TableAPI>(null);23tableRef.current?.setPivot({4 rows: ["region"],5 columns: ["quarter"],6 values: [{ accessor: "sales", aggregation: { type: "sum" } }],7});8tableRef.current?.setPivot(null); // back to source rows
- •
setPivot(config | null)— enable, update, or clear pivot - •
getPivot()— current config - •
getPivotHeaders()/getPivotedRows()— inspect the generated matrix
React Pivot Table Behavior Notes
- Filters run on source rows before pivoting. Row-dimension columns keep their source accessors, so filtering by region still works. Generated measure columns are not filterable.
- Sort and quick filter apply to the pivoted view.
- CSV export exports the pivoted matrix, not the original fact table.
- Pivoted measure cells are aggregated summaries—not meant for cell editing.
- High column cardinality (many distinct column-field values) creates many leaf columns. Watch horizontal scroll and performance.
Pivot Panel: Enable enablePivotPanel with the column editor so end users place fields into Rows, Columns, and Values. Declarative pivot stays the foundation; the panel drives the same config.
React Pivot Table FAQ
What is a React pivot table?
A React pivot table reshapes flat rows into a matrix: row dimensions stay on the left, column dimensions become dynamic headers, and value fields are aggregated (sum, average, count, min, max, or custom) into each cell.
Is there a free alternative to AG Grid pivot mode?
Yes. Simple Table provides declarative matrix pivot without AG Grid Enterprise. You configure rows, columns, and values via props or TableAPI, or use enablePivotPanel in the column editor for an in-table Pivot Panel.
When should I use pivot vs row grouping in a React data grid?
Use matrix pivot when you need cross-tab columns generated from data and aggregated cells. Use row grouping when you still need individual fact rows in an expand/collapse hierarchy with fixed columns.
Does Simple Table include a Pivot Panel?
Yes. Set enablePivotPanel (with enableColumnEditor) to place fields into Rows, Columns, and Values from the column editor. The panel drives the same pivot config API as props and setPivot.
Can I update a React pivot table at runtime?
Yes. Swap a controlled pivot prop, use the Pivot Panel, or call TableAPI.setPivot to enable, change, or clear pivot. getPivot, getPivotHeaders, and getPivotedRows inspect the active matrix.
Ship a React Pivot Table Without Waiting on Enterprise
You can ship a React pivot table today without AG Grid Enterprise or hand-rolled matrix math. With a declarative pivot config you get:
- Row / column / value dimensions with sum, average, count, and more
- Nested dimensions and row/column/grand totals
- Runtime updates via TableAPI for analytics presets
- An in-table Pivot Panel (
enablePivotPanel) on the same config model