Tables
Show the data behind a decision as a table in a Node.js trace, with highlighted rows, summary rows and labelled sections.
The recount.table() builder constructs a single TableData object. Call .build() to get a value ready to pass directly as span input or output.
Basic usage
recount.addSpan('table', 'Policy checks', {
output: recount
.table('Validation Results')
.fromRecords([
{ check: 'Policy active', result: 'Pass' },
{ check: 'Cover active at incident', result: 'Pass' },
{ check: 'Comprehensive cover', result: 'Pass' }
])
.highlightRows((row) => (row.result === 'Pass' ? 'success' : 'danger'))
.build()
});recount.table(title?)
Returns a TableBuilder. Chain methods and call .build() to get a TableData object, ready to use as span input or output.
Data sources
.fromRecords(data)
Build from an array of objects. Column names are the object keys as-is.
recount
.table('Users')
.fromRecords([
{ name: 'Alice', score: 98.5 },
{ name: 'Bob', score: 72.1 }
])
.build();.fromObject(data)
Build a key-value table from a plain object. Renders as two columns: Key and Value.
recount
.table('Config')
.fromObject({ timeout: 5000, retries: 3, env: 'production' })
.build();Column selection
.pick(...keys)
Only include the specified columns, in order.
.pick('name', 'email', 'role')Labels & formatting
.label(map)
Override column display labels.
.label({ usageKwh: 'Usage (kWh)', ratePerKwh: 'Rate ($/kWh)' }).round(decimals)
Round all numeric values to decimals decimal places.
.round(2).transformValues(map)
Apply a transform function to values in specific columns.
.transformValues({
status: (v) => String(v).toUpperCase(),
createdAt: (v) => new Date(v as string).toLocaleDateString(),
})Highlighting
.highlightColumn(key, highlight)
Apply a highlight color to an entire column header and cells.
.highlightColumn('revenue', 'success').highlightRows(fn)
Apply a per-row highlight based on the row's data.
.highlightRows((row) => {
if ((row.errorRate as number) > 0.1) return 'danger';
if ((row.errorRate as number) > 0.05) return 'warn';
return null;
}).highlightCells(key, fn)
Apply a per-cell highlight for a specific column.
.highlightCells('status', (v) => {
if (v === 'error') return 'danger';
if (v === 'ok') return 'success';
return null;
})Highlight values: 'danger' | 'warn' | 'success' | 'info' | 'muted'
Column spans
.spanColumn(key, span)
Make a column header span multiple columns.
.spanColumn('metrics', 3)Extra rows
.appendRow(cells, highlight?)
Append a summary row at the bottom of the table.
.appendRow(['Total', 450, 890], 'info')Use recount.spanCell(value, span) to create a cell that spans multiple columns:
.appendRow([recount.spanCell('Grand total: $1,234', 4)], 'success').summary(stats)
Define stats shown when this table is collapsed in the dashboard. Each stat has a text string and an optional highlight color.
.summary([
{ text: '$64.70', highlight: 'info' },
{ text: '28.8% less', highlight: 'success' },
])Highlight values: 'danger' | 'warn' | 'success' | 'info' | 'muted'
.buildSection()
Returns a TableSection (rows and optional highlights/summary, without column definitions). Used as input to recount.tableSections() when building sectioned tables.
const section = recount
.table('Active policies')
.fromRecords(activePolicies)
.highlightRows((row) => (row.overdue ? 'danger' : null))
.buildSection();recount.tableSections(options)
Builds a single table with named sections that share the same columns. Use this when you want to group rows under labelled headings within one table span.
recount.addSpan('table', 'Plan comparison', {
output: recount.tableSections({
title: 'Coverage breakdown',
columns: ['Benefit', 'Current plan', 'Recommended plan'],
sections: [
recount
.table('Medical')
.fromRecords([
{
Benefit: 'Hospital',
'Current plan': '$500',
'Recommended plan': '$250'
},
{
Benefit: 'Specialist',
'Current plan': 'Not covered',
'Recommended plan': '$50'
}
])
.highlightRows((row) =>
row['Recommended plan'] === 'Not covered' ? 'warn' : null
),
recount.table('Extras').fromRecords([
{
Benefit: 'Dental',
'Current plan': 'Not covered',
'Recommended plan': '80%'
},
{ Benefit: 'Optical', 'Current plan': '50%', 'Recommended plan': '80%' }
])
]
})
});Options
| Option | Type | Description |
|---|---|---|
title | string | Optional title for the whole table |
columns | TableColumn[] | Column definitions shared across all sections. Can be omitted when the first section is a TableBuilder; columns are derived from it automatically |
sections | (TableBuilder | TableSection)[] | At least one section. Pass TableBuilder instances (built with .buildSection() internally) or raw TableSection objects |
When columns is omitted, the first section must be a TableBuilder instance, not a plain object.
Raw TableSection objects
Sections can also be plain objects instead of builder instances:
recount.tableSections({
columns: ['Region', 'Claims', 'Avg settlement'],
sections: [
{
title: 'Q1',
rows: [
['NSW', 142, '$4,200'],
['VIC', 98, '$3,800']
]
},
{
title: 'Q2',
rows: [
['NSW', 167, '$4,500'],
['VIC', 110, '$4,100']
]
}
]
});recount.spanCell(value, span)
Creates a cell that spans span columns. Only useful inside .appendRow().
recount.spanCell('Total Cost: $99.00', 3);Multiple tables
To display multiple tables that share the same columns as labelled sections, use recount.tableSections().
To display distinct tables together, use a group span. Each table is its own span inside the group:
recount.addGroup('Claim report', (g) => {
g.span('table', 'Summary', {
output: recount
.table('Summary')
.fromObject({
claimId: 'CLM-2024-03941',
decision: 'Approved',
settlement: '$6,840.00'
})
.build()
});
g.span('table', 'Breakdown', {
output: recount
.table('Breakdown')
.fromRecords([
{ item: 'Vehicle repairs', amount: 5200 },
{ item: 'Rental car', amount: 840 },
{ item: 'Medical', amount: 800 }
])
.round(2)
.build()
});
});Shorthand exports
For simple cases where you don't need to chain builder methods, two direct exports are available:
recount.tableFromRecords({ data, title? })
Equivalent to recount.table(title).fromRecords(data).build(). Returns TableData directly.
recount.addSpan('table', 'Policy checks', {
output: recount.tableFromRecords({
title: 'Validation Results',
data: [
{ check: 'Policy active', result: 'Pass' },
{ check: 'Cover active at incident', result: 'Pass' }
]
})
});recount.tableFromObject({ data, title? })
Equivalent to recount.table(title).fromObject(data).build(). Returns TableData directly.
recount.addSpan('table', 'Claim summary', {
output: recount.tableFromObject({
title: 'Claim Details',
data: {
claimId: 'CLM-2024-03941',
vehicle: '2019 Toyota Camry',
decision: 'Approved'
}
})
});