Formatting Presets
Formatting presets help Pivot reports show numbers, money, percentages, and dates in a readable way. Conditional formatting presets then help users spot high revenue, low margin, or other important analytical values.
Open the full demo and framework source.Formatting changes display, not input eligibility or arithmetic. Percentage calculations store ratios (0.5 means 50%); a percentage format does not divide the value again. Configure null/invalid/count semantics through Aggregation policies and preserve those operations when saving reports.
Basic Setup
Section titled “Basic Setup”Import the helpers from @revolist/pivot and create reusable formatters for the value types in your report:
import { createPivotValueFormatter, formatPivotValue, pivotConditionalFormattingPresets, createPivotConditionalCellProperties, PivotPlugin, type PivotConfig,} from '@revolist/pivot';
const revenueFormatter = createPivotValueFormatter({ preset: 'currency', currency: 'USD', locale: 'en-US', options: { maximumFractionDigits: 0 },});
const marginFormatter = createPivotValueFormatter({ preset: 'percent', locale: 'en-US', options: { minimumFractionDigits: 1, maximumFractionDigits: 1 },});createPivotValueFormatter() returns a function. Use it when the same formatting rule is reused by many cells. Use formatPivotValue() when you only need to format one value:
const formattedLabel = formatPivotValue(null, { preset: 'date', nullDisplay: 'No close date',});Value Formatters
Section titled “Value Formatters”Formatting presets
Null and invalid display fallback without changing aggregate data
Pivot formatters are display helpers. They do not change the original source data or the aggregated number that Pivot calculates. Keep your source values as real numbers and dates, then format them at render time.
const columnTypes = { pivotCurrency: { cellTemplate: (_h, props) => revenueFormatter(props.value), cellProperties: () => ({ class: { 'align-right': true } }), }, pivotPercent: { cellTemplate: (_h, props) => marginFormatter(props.value), cellProperties: () => ({ class: { 'align-right': true } }), },};Attach those column types to the Pivot dimensions that produce analytical value cells:
const pivot: PivotConfig = { dimensions: [ { prop: 'region', name: 'Region' }, { prop: 'closeDate', name: 'Close date', columnType: 'pivotDate' }, { prop: 'segment', name: 'Segment' }, { prop: 'revenue', name: 'Revenue', columnType: 'pivotCurrency' }, { prop: 'marginRate', name: 'Margin', columnType: 'pivotPercent' }, ], rows: ['region', 'closeDate'], columns: ['segment'], values: [ { prop: 'revenue', aggregator: 'sum', label: 'Revenue' }, { prop: 'marginRate', aggregator: 'avg', label: 'Avg margin' }, ],};Locale And Presets
Section titled “Locale And Presets”The formatter presets use the browser Intl formatters. Choose the preset that matches the value:
number: plain numeric values such as counts, units, or scores.currency: money values. Always providecurrency, for example"USD"or"EUR".percent: ratio values such as0.315, displayed as31.5%.date: date-only values.datetime: date and time values.
const integerFormatter = createPivotValueFormatter({ preset: 'number', locale: 'en-US', options: { maximumFractionDigits: 0 },});
const eurFormatter = createPivotValueFormatter({ preset: 'currency', currency: 'EUR', locale: 'de-DE',});
const dateFormatter = createPivotValueFormatter({ preset: 'date', locale: 'en-US', options: { month: 'short', day: '2-digit', year: 'numeric' },});Conditional Formatting Presets
Section titled “Conditional Formatting Presets”Use pivotConditionalFormattingPresets to describe matching rules, and createPivotConditionalCellProperties() to turn those rules into a RevoGrid cellProperties function.
const conditionalCellProperties = createPivotConditionalCellProperties( [ pivotConditionalFormattingPresets.gt(300000, { field: 'revenue', style: { backgroundColor: 'rgba(22, 163, 74, 0.16)', color: '#166534', fontWeight: '600', }, }), pivotConditionalFormattingPresets.lt(0.28, { field: 'marginRate', style: { backgroundColor: 'rgba(220, 38, 38, 0.14)', color: '#991b1b', fontWeight: '600', }, }), pivotConditionalFormattingPresets.between(0.28, 0.34, { field: 'marginRate', style: { backgroundColor: 'rgba(234, 179, 8, 0.14)', color: '#854d0e', }, }), ], { match: 'all' },);Available presets:
gt(value, props): greater than a number.lt(value, props): less than a number.between(min, max, props): between two numbers, including both bounds.equal(value, props): equal to a value.textContains(value, props): contains text.
The optional field narrows a rule to a generated value field. For example, field: 'revenue' applies to generated revenue cells even when Pivot creates column paths such as Software|revenue.
Analytical Cells
Section titled “Analytical Cells”By default, createPivotConditionalCellProperties() only formats Pivot analytical cells. These are generated cells from the values area, not row header fields such as region or closeDate.
This default prevents a rule like gt(300000) from accidentally styling row dimensions that happen to contain comparable values. If you intentionally want rules to apply outside analytical value cells, enable includeNonAnalytical:
const allCellProperties = createPivotConditionalCellProperties(rules, { includeNonAnalytical: true,});Most Pivot reports should keep the default and attach conditional formatting to value dimensions:
const pivot: PivotConfig = { dimensions: [ { prop: 'region', name: 'Region' }, { prop: 'revenue', name: 'Revenue', columnType: 'pivotCurrency', cellProperties: conditionalCellProperties, }, { prop: 'marginRate', name: 'Margin', columnType: 'pivotPercent', cellProperties: conditionalCellProperties, }, ], rows: ['region'], columns: ['segment'], values: [ { prop: 'revenue', aggregator: 'sum' }, { prop: 'marginRate', aggregator: 'avg' }, ],};Practical Example
Section titled “Practical Example”This report groups opportunities by region and close date, splits generated value columns by segment, formats revenue as currency, formats margin as a percent, and highlights high revenue or weak margin.
const rows = [ { region: 'North America', closeDate: '2026-01-16', segment: 'Software', revenue: 184000, marginRate: 0.37 }, { region: 'North America', closeDate: '2026-01-22', segment: 'Services', revenue: 126000, marginRate: 0.31 }, { region: 'EMEA', closeDate: '2026-02-06', segment: 'Services', revenue: 118000, marginRate: 0.28 },];
const pivot: PivotConfig = { dimensions: [ { prop: 'region', name: 'Region' }, { prop: 'closeDate', name: 'Close date', columnType: 'pivotDate' }, { prop: 'revenue', name: 'Revenue', columnType: 'pivotCurrency', cellProperties: conditionalCellProperties, }, { prop: 'marginRate', name: 'Margin', columnType: 'pivotPercent', cellProperties: conditionalCellProperties, }, ], rows: ['region', 'closeDate'], columns: ['segment'], values: [ { prop: 'revenue', aggregator: 'sum', label: 'Revenue' }, { prop: 'marginRate', aggregator: 'avg', label: 'Avg margin' }, ], totals: { subtotals: true, grandTotal: true, }, groupLabels: { null: formatPivotValue(null, { preset: 'date', nullDisplay: 'No close date' }), },};
const grid = document.querySelector('revo-grid');grid.columnTypes = columnTypes;grid.plugins = [PivotPlugin];grid.pivot = pivot;grid.source = rows;Common Mistakes
Section titled “Common Mistakes”- Formatting the source data before Pivot aggregates it. Keep values numeric so
sum,avg, and comparisons work correctly. - Using
preset: 'percent'with whole percentages.31.5%should usually be stored as0.315, not31.5. - Forgetting
currencywhen using thecurrencypreset. - Expecting conditional formatting to affect row fields by default. It targets analytical value cells unless
includeNonAnalyticalis enabled. - Omitting
fieldon a conditional rule when the report has several value fields. Withoutfield, the rule can match every analytical value cell. - Expecting
cellTemplateformatting to change conditional comparisons. Conditional rules evaluate the raw cell value, not the formatted display string.
Continue with Sorting And Filtering or Configuration Reference.