Aggregation is independent from column grouping. Register rowAggregationFeature whenever columns calculate totals or aggregated values. Add columnGroupingFeature separately only when the table also groups rows.
For the complete behavior and type reference, see the core Aggregation Guide.
Register only the built-in functions referenced by name. Passing a definition directly to a column does not require a registry entry.
import {
rowAggregationFeature,
aggregationFn_count,
aggregationFn_extent,
aggregationFn_mean,
aggregationFn_sum,
tableFeatures,
useTable,
} from '@tanstack/react-table'
const features = tableFeatures({
rowAggregationFeature,
aggregationFns: {
count: aggregationFn_count,
extent: aggregationFn_extent,
mean: aggregationFn_mean,
sum: aggregationFn_sum,
},
})
const table = useTable({
features,
columns,
data,
})The aggregation feature does not require a grouped row model. This makes grand totals and custom row-subset totals available in otherwise ordinary tables.
A column accepts one aggregation or an array. A single entry returns a scalar; multiple entries return an object keyed by the aggregation name or descriptor id.
columnHelper.accessor('amount', {
aggregationFn: 'sum',
})
columnHelper.accessor('score', {
aggregationFn: ['count', 'mean', { id: 'range', aggregationFn: 'extent' }],
})String values remain backward-compatible. Use descriptors when a result needs a stable custom key or options.
Call column.getAggregationValue() without arguments to aggregate the default pre-grouped row model. Filtering is included; grouping, sorting, expansion, and pagination do not change that default total.
footer: ({ column }) => column.getAggregationValue<number>().toLocaleString()Pass one options object with rows from any row model to choose a different set:
column.getAggregationValue({ rows: table.getCoreRowModel().rows })
column.getAggregationValue({ rows: table.getRowModel().rows })
column.getAggregationValue({ rows: table.getFilteredSelectedRowModel().rows })
column.getAggregationValue({ rows: table.getCoreRowModel().rows.slice(0, 3) })
column.getAggregationValue({ rows: table.getCoreRowModel().rows, maxDepth: 1 })Depth is relative to the supplied row array. 0 selects those roots, 1 selects their direct sub-rows, and Infinity selects terminal rows. Configure maxAggregationDepth on the column for cached default calls, or pass maxDepth in the options object as an explicit override. table.getMaxSubRowDepth() returns the deepest structural depth in the core row model. Column option getAggregationValue(context) can provide an external or server-computed value; return undefined to fall back to the configured aggregation function.
Grouped aggregation composes two independent features. Register both, add the grouped row-model slot, and configure aggregation functions on the columns that should produce grouped values.
const features = tableFeatures({
rowAggregationFeature,
columnGroupingFeature,
groupedRowModel: createGroupedRowModel(),
aggregationFns: { sum: aggregationFn_sum },
})
columnHelper.accessor('visits', {
aggregationFn: 'sum',
aggregatedCell: ({ getValue }) => getValue<number>().toLocaleString(),
footer: ({ column }) => column.getAggregationValue<number>().toLocaleString(),
})Use cell.getIsAggregated() to identify a grouped aggregate cell. Footer rendering uses the adapter's normal footer renderer.
Use constructAggregationFn({ aggregate, merge? }) for custom definitions. The aggregate context includes depth-selected rows, maxDepth, getValue, column, and table. Every aggregation configured on a column receives the same row frontier. Grouped calls also include groupingRow and immediate subRows for custom structural behavior. A merge implementation can more efficiently combine already-computed sub-row results.
See Custom Aggregation Definitions for the full contract, return typing, caching behavior, and worker limitations.