Aggregation and Grouping Example
Grouping and Aggregation features are usually hard to implement, but MRT (thanks to TanStack Table) makes it easy. Once enabled, simply click the vertical ellipses (⋮) icon for the column you want to group by and select Group by (column name).
You can group by a single column or multiple columns at a time. Then, you can run aggregations on grouped columns to calculate totals, averages, max, min, etc.
The Grouping and Aggregation features work hand in hand with the Expanding and Sorting features. Try grouping by various columns in the example below and sorting by the aggregated columns, such as "age" or "salary".
State | First Name | Last Name | Age | Gender | Salary | |
---|---|---|---|---|---|---|
Alabama (7) | Oldest by State: 64 | Average by State: $43,375 | ||||
Thad | Wiegand | 64 | Female | $56,146 | ||
Alivia | Ledner | 56 | Male | $12,591 | ||
Danyka | Gleason | 36 | Male | $71,238 | ||
Lionel | Hartmann | 30 | Nonbinary | $58,743 | ||
Reinhold | Reichel | 30 | Female | $30,531 | ||
Lurline | Koepp | 59 | Female | $10,645 | ||
Kody | Braun | 38 | Female | $63,733 | ||
Alaska (8) | Oldest by State: 59 | Average by State: $68,901 | ||||
Eloisa | Kohler | 31 | Male | $45,801 | ||
Kian | Hand | 56 | Male | $81,062 | ||
Loyce | Schmidt | 29 | Female | $76,295 | ||
Michale | Collier | 59 | Male | $75,197 | ||
Eldridge | Stroman | 42 | Male | $59,594 | ||
Alvera | Balistreri | 25 | Female | $79,844 | ||
Kayden | Emard | 35 | Female | $98,252 | ||
Domingo | Bauch | 36 | Female | $35,159 | ||
Arizona (1) | Oldest by State: 22 | Average by State: $54,027 | ||||
Gunner | Rolfson | 22 | Male | $54,027 | ||
Arkansas (4) | Oldest by State: 52 | Average by State: $58,194 | ||||
Max Age: 65 | Average Salary: $56,319 |
1import React, { useMemo } from 'react';2import { Box, Stack } from '@mui/material';3import MaterialReactTable, { MRT_ColumnDef } from 'material-react-table';4import { data, Person } from './makeData';56const Example = () => {7 const averageSalary = useMemo(8 () => data.reduce((acc, curr) => acc + curr.salary, 0) / data.length,9 [],10 );1112 const maxAge = useMemo(13 () => data.reduce((acc, curr) => Math.max(acc, curr.age), 0),14 [],15 );1617 const columns = useMemo<MRT_ColumnDef<Person>[]>(18 () => [19 {20 header: 'First Name',21 accessorKey: 'firstName',22 enableGrouping: false, //do not let this column be grouped23 },24 {25 header: 'Last Name',26 accessorKey: 'lastName',27 },28 {29 header: 'Age',30 accessorKey: 'age',31 aggregationFn: 'max', //show the max age in the group (lots of pre-built aggregationFns to choose from)32 //required to render an aggregated cell33 AggregatedCell: ({ cell, table }) => (34 <>35 Oldest by{' '}36 {table.getColumn(cell.row.groupingColumnId ?? '').columnDef.header}:{' '}37 <Box38 sx={{ color: 'info.main', display: 'inline', fontWeight: 'bold' }}39 >40 {cell.getValue<number>()}41 </Box>42 </>43 ),44 Footer: () => (45 <Stack>46 Max Age:47 <Box color="warning.main">{Math.round(maxAge)}</Box>48 </Stack>49 ),50 },51 {52 header: 'Gender',53 accessorKey: 'gender',54 //optionally, customize the cell render when this column is grouped. Make the text blue and pluralize the word55 GroupedCell: ({ cell, row }) => (56 <Box sx={{ color: 'primary.main' }}>57 <strong>{cell.getValue<string>()}s </strong> ({row.subRows?.length})58 </Box>59 ),60 },61 {62 header: 'State',63 accessorKey: 'state',64 },65 {66 header: 'Salary',67 accessorKey: 'salary',68 aggregationFn: 'mean',69 //required to render an aggregated cell, show the average salary in the group70 AggregatedCell: ({ cell, table }) => (71 <>72 Average by{' '}73 {table.getColumn(cell.row.groupingColumnId ?? '').columnDef.header}:{' '}74 <Box sx={{ color: 'success.main', fontWeight: 'bold' }}>75 {cell.getValue<number>()?.toLocaleString?.('en-US', {76 style: 'currency',77 currency: 'USD',78 minimumFractionDigits: 0,79 maximumFractionDigits: 0,80 })}81 </Box>82 </>83 ),84 //customize normal cell render on normal non-aggregated rows85 Cell: ({ cell }) => (86 <>87 {cell.getValue<number>()?.toLocaleString?.('en-US', {88 style: 'currency',89 currency: 'USD',90 minimumFractionDigits: 0,91 maximumFractionDigits: 0,92 })}93 </>94 ),95 Footer: () => (96 <Stack>97 Average Salary:98 <Box color="warning.main">99 {averageSalary?.toLocaleString?.('en-US', {100 style: 'currency',101 currency: 'USD',102 minimumFractionDigits: 0,103 maximumFractionDigits: 0,104 })}105 </Box>106 </Stack>107 ),108 },109 ],110 [averageSalary, maxAge],111 );112113 return (114 <MaterialReactTable115 columns={columns}116 data={data}117 enableColumnResizing118 enableGrouping119 enableStickyHeader120 enableStickyFooter121 initialState={{122 density: 'compact',123 expanded: true, //expand all groups by default124 grouping: ['state'], //an array of columns to group by by default (can be multiple)125 pagination: { pageIndex: 0, pageSize: 20 },126 sorting: [{ id: 'state', desc: false }], //sort by state by default127 }}128 muiToolbarAlertBannerChipProps={{ color: 'primary' }}129 muiTableContainerProps={{ sx: { maxHeight: 700 } }}130 />131 );132};133134export default Example;135
View Extra Storybook Examples