Multiple Measures and Values on Rows
A report can show more than one calculation at once. For example, compare total Sales and average Sales for the same Region and Quarter. Give each measure a clear label so users can tell them apart.
import type { PivotConfig } from '@revolist/pivot';
const values: PivotConfig['values'] = [ { id: 'sales-total', prop: 'sales', aggregator: 'sum', label: 'Total sales' }, { id: 'sales-average', prop: 'sales', aggregator: 'avg', label: 'Average sales', },];Try the live layout example below. Switch the position of Values and compare the same calculations horizontally and vertically. Aggregation policies explain the operations; chart data selection explains how these measures become chart series.
By default, Pivot renders measures as generated value columns. valuesOnRows flips that layout so measures become synthetic row members instead.
Open the full demo and framework source.
Try it
Section titled “Try it”Values on rows
Switch between Values as columns, Values at beginning/middle/end
Default Layout vs Values On Rows
Section titled “Default Layout vs Values On Rows”Default layout:
rows: Regioncolumns: Quartervalues: Sales, MarginThis usually produces:
- one row branch per region
- one generated value column per quarter and measure
With valuesOnRows: true, the same measures become row members:
- Region
- Sales
- Margin
That is useful when:
- you have many measures and few row dimensions
- you want a more compact column area
- users compare measures vertically rather than horizontally
Configuration
Section titled “Configuration”const pivot: PivotConfig = { rows: ['region'], columns: ['quarter'], values: [ { prop: 'sales', aggregator: 'sum' }, { prop: 'margin', aggregator: 'avg' }, ], valuesOnRows: true,};Explicit Values Position
Section titled “Explicit Values Position”Use rowTree with the $values pseudo-field when measures need to appear at a specific hierarchy level:
rowTree: ['carModel', 'cellId', '$values'];rowTree: ['carModel', '$values', 'cellId'];rowTree: ['$values', 'carModel', 'cellId'];rowTree is the explicit advanced API. If it is provided, it controls value placement even when valuesOnRows is also set.
What Changes Internally
Section titled “What Changes Internally”- Pivot adds a synthetic row field called
Values. - Generated value columns become value labels in the row hierarchy.
- Grouping and row drill-down now treat the value label as part of the row structure.
This is why row drill-down helpers account for valuesOnRows when deriving row props.
Tradeoffs
Section titled “Tradeoffs”Benefits:
- fewer generated columns
- easier comparison of multiple measures
- clearer layouts on narrow screens
Costs:
- more synthetic rows
- row drill-down can feel deeper because the value label becomes part of the hierarchy
- users expecting a spreadsheet-style “measures across columns” layout may find it less familiar
When Not To Use It
Section titled “When Not To Use It”Avoid valuesOnRows when:
- you only have one measure
- your users think in terms of wide analytical columns
- you already have a deep row hierarchy and want to keep rows compact
Continue with Drill-Down to see how row and column expansion behave in both layouts.