React Pivot Table
"Break revenue down by region and quarter" is a spreadsheet export for most teams. Here it is a drag: drop dimensions onto the Rows and Columns axes, pick a measure and an aggregation, and the crosstab recomputes with row, column, and grand totals.
Available
Rows
Columns
| Region | Q1 | Q2 | Q3 | Q4 | Total |
|---|---|---|---|---|---|
| APAC | $1715k | $1854k | $1547k | $1469k | $6585k |
| Americas | $1555k | $1045k | $1204k | $1056k | $4860k |
| EMEA | $662k | $1266k | $1638k | $2013k | $5579k |
| Total | $3932k | $4165k | $4389k | $4538k | $17024k |
Installation
Props
| Prop | Type | Description |
|---|---|---|
| data | T[] | The flat records to aggregate |
| fields | PivotField[] | { key, label, kind: "dimension" \ |
| defaultRows | string[] | Dimension keys on the row axis |
| defaultCols | string[] | Dimension keys on the column axis |
| defaultValue | string | Measure key for the value slot |
| defaultAgg | Aggregation | sum, count, avg, min, or max |
| formatValue | (v: number) => string | Cell formatter |
Dimensions, measures, and empty cells
The distinction the whole component turns on: dimensions are what you group by (region, quarter), measures are what you aggregate (revenue, units). Only dimensions can land on the axes; measures fill the value slot. count needs no measure and ignores the selected one.
Axis assignment is drag-and-drop between the four zones, and each chip is also removable — dragging is the fast path, not the only one, which keeps it usable on a trackpad. A cell with no matching records renders as a dot, not a zero: "no data for this combination" is genuinely different from "aggregates to zero", and collapsing the two hides real gaps in the data.
Aggregation runs client-side over the full data array, so this is the right tool for the thousands-of-rows range. Past that, pre-aggregate on the server and feed the result in.
New components every week
Get the week's new Kelvin UI components and templates in one short email. No spam, unsubscribe anytime.