MRT logoMantine React Table

On This Page

    Aggregation and Grouping Feature Guide

    Mantine React Table has built-in grouping and aggregation features. There are options for both automatic client-side grouping and aggregation, as well as manual server-side grouping and aggregation. This guide will walk you through the different options and how to use and customize them.

    Relevant Table Options

    1
    Record<string, AggregationFn>
    TanStack Table Grouping Docs
    2
    boolean
    true
    MRT Expanding Sub Rows Docs
    3
    boolean
    MRT Aggregation and Grouping Docs
    4
    boolean
    5
    (table: Table<TData>) => () => RowModel<TData>
    TanStack Table Grouping Docs
    6
    false | 'reorder' | 'remove'
    reorder
    TanStack Table Grouping Docs
    7
    BadgeProps| ({ table }} => BadgeProps
    Mantine Chip Docs
    8
    boolean
    TanStack Table Grouping Docs
    9
    OnChangeFn<GroupingState>
    TanStack Table Grouping Docs
    10
    'bottom' | 'top' | 'head-overlay' | 'none'

    Relevant Column Options

    1
    ({ cell, column, row, table }) => ReactNode
    2
    ReactNode | ({ column, footer, table }) => ReactNode
    MRT Data Columns Docs
    3
    ({ cell, column, row, table }) => ReactNode
    4
    boolean

    Relevant State

    1
    Record<string, boolean> | boolean
    {}
    TanStack Table Expanding Docs
    2
    Array<string>
    []
    TanStack Table Grouping Docs

    Enable Grouping

    To enable grouping, set the enableGrouping table option to true. This will both add a drag handle button so that columns can be dragged to the dropzone to be grouped and will add an entry column actions menu to group or ungroup a column.
    const table = useMantineReactTable({
    columns,
    data,
    enableGrouping: true, //enable grouping
    });

    Disable Grouping Per Column

    const columns = [
    {
    accessorKey: 'name',
    header: 'Name',
    enableGrouping: false, // disable grouping for this column
    },
    {
    accessorKey: 'age',
    header: 'Age',
    },
    ];
    const table = useMantineReactTable({
    columns,
    data,
    enableGrouping: true, //enable grouping
    });
    return <MantineReactTable table={table} />;

    Hide Drag Buttons for Grouping

    If you do not want the drag buttons that come with the grouping feature, you can independently disable them without disabling the grouping feature entirely by setting the enableColumnDragging table option to false.
    const table = useMantineReactTable({
    columns,
    data,
    enableGrouping: true,
    enableColumnDragging: false, //do not show drag handle buttons, but still show grouping options in column actions menu
    });

    Group Columns by Default

    If you want columns to be grouped by default, you can set the grouping state in either the initialState or state table options.
    const table = useMantineReactTable({
    columns,
    data,
    enableGrouping: true,
    initialState: { grouping: ['location', 'department'] }, //group by location and department by default
    });

    Expand Grouped Rows by Default

    In addition to grouping columns by default, you may also want those grouped rows to be expanded and visible by default, too. You can do this by setting the expanded state to true in either the initialState or state table options.
    const table = useMantineReactTable({
    columns,
    data,
    enableGrouping: true,
    initialState: {
    grouping: ['location', 'department'], //group by location and department by default and expand grouped rows
    expanded: true, //show grouped rows by default
    },
    });

    Aggregation on Grouped Rows

    One of the cool features of Mantine React Table is that it can automatically aggregate the data in grouped rows. To enable this, you must specify both an aggregationFn and an AggregatedCell render option on a column definition.

    Built-in Aggregation Functions

    There are several built-in aggregation functions available that you can use. They are:
    • count - Finds the number of rows in a group
    • extent - Finds the minimum and maximum values of a group of rows
    • max - Finds the maximum value of a group of rows
    • mean - Finds the average value of a group of rows
    • median - Finds the median value of a group of rows
    • min - Finds the minimum value of a group of rows
    • sum - sums the values of a group of rows
    • uniqueCount - Finds the number of unique values of a group of rows
    • unique - Finds the unique values of a group of rows
    All of these built-in aggregation functions are from TanStack Table
    const columns = [
    {
    accessorKey: 'team', //grouped by team in initial state below
    header: 'Team',
    },
    {
    accessorKey: 'player',
    header: 'Player',
    },
    {
    accessorKey: 'points',
    header: 'Points',
    aggregationFn: 'sum', //calc total points for each team by adding up all the points for each player on the team
    AggregatedCell: ({ cell }) => <div>Team Score: {cell.getValue()}</div>,
    },
    ];
    const table = useMantineReactTable({
    columns,
    data,
    enableGrouping: true,
    initialState: { grouping: ['team'], expanded: true },
    });
    return <MantineReactTable table={table} />;

    Custom Aggregation Functions

    If none of these pre-built aggregation functions work for you, you can also pass in a custom aggregation function. The aggregation function will be passed in an array of values from the column that you are aggregating. It should return a single value that will be displayed in the aggregated cell.
    If you are specifying a custom aggregation function, it must implement the following type:
    export type AggregationFn<TData extends AnyData> = (
    getLeafRows: () => Row<TData>[],
    getChildRows: () => Row<TData>[]
    ) => any
    Mantine React Table does not automatically aggregate all rows for you to calculate totals for the entire table. However, it is still easy enough to do this manually and add in your custom calculations into the footer or Footer of a column definition. It is recommended that you do any necessary aggregation calculations on your data in a useMemo hook before passing it to the columns footer in your columns definition.
    //calculate the total points for all players in the table in a useMemo hook
    const averageScore = useMemo(() => {
    const totalPoints = data.reduce((acc, row) => acc + row.points, 0);
    const totalPlayers = data.length;
    return totalPoints / totalPlayers;
    }, [data]);
    const columns = [
    {
    accessorKey: 'name',
    header: 'Name',
    },
    {
    accessorKey: 'score',
    header: 'Score',
    Footer: () => <div>Average Score: {averageScore}</div>, //do not do calculations in render, do them in useMemo hook and pass them in here
    },
    ];
    Please remember to perform heavy aggregation calculations in a useMemo hook to avoid unnecessary re-renders!

    Custom Cell Renders for Aggregation and Grouping

    There are a few custom cell render overrides that you should be aware of when using grouping and aggregation features.

    AggregatedCell Column Option

    "Aggregation Cells" are cells in an aggregated row (not a normal data row) that can display aggregates (avg, sum, etc.) of the data in a group. The cell that the table is grouped on, however, is not an Aggregate Cell, but rather a GroupedCell.
    You can specify the custom render for these cells with the AggregatedCell render option on a column definition.
    const columns = [
    {
    accessorKey: 'points',
    header: 'Points',
    aggregationFn: 'sum',
    AggregatedCell: ({ cell }) => <div>Total Score: {cell.getValue()}</div>,
    },
    ];

    GroupedCell Column Option

    "Grouped Cells" are cells in a grouped row (not a normal data row) that by default display the value that the rows are grouped on and the number of rows in the group. You can override the default render for these cells with the GroupedCell render option on a column definition.
    const columns = [
    {
    accessorKey: 'team',
    header: 'Team',
    GroupedCell: ({ cell }) => <div>Team: {cell.getValue()}</div>,
    },
    ];

    PlaceholderCell Column Option

    "Placeholder Cells" are cells that are usually meant to be empty in grouped rows and columns. They are simply rendered with a value of null by default, but you can override the default render for these cells with the PlaceholderCell render option on a column definition.
    const columns = [
    {
    accessorKey: 'team',
    header: 'Team',
    PlaceholderCell: ({ cell, row }) => (
    <div>{row.original.someOtherRowValue}</div>
    ),
    },
    ];

    Aggregation/Grouping Example

    Alabama (2)Oldest by State:
    42
    Average by State:
    $71,105
    CelineJohnston42Non-binary$96,445
    HarmonBode14Female$45,764
    Alaska (7)Oldest by State:
    79
    Average by State:
    $61,315
    JulietUpton13Male$43,447
    MartinaMiller79Male$59,714
    HerbertLebsack33Female$68,645
    VivianRempel30Female$89,537
    RickWill36Female$48,064
    GuiseppeHeller31Female$20,924
    BenDooley34Non-binary$98,876
    Arizona (8)Oldest by State:
    77
    Average by State:
    $66,775
    SamanthaDibbert48Male$31,884
    JevonWuckert52Male$88,064
    LiaLowe77Male$56,479
    AbagailLuettgen25Male$99,154
    AlanisKuhic5Male$93,668
    ArvidAuer8Male$59,826
    RosellaBlanda54Female$76,754
    NathenWaelchi55Female$28,373
    Max Age:
    80
    Average Salary:
    $57,062
    1-20 of 298
    1
    import { useMemo } from 'react';
    2
    import { Box, Stack } from '@mantine/core';
    3
    import {
    4
    MantineReactTable,
    5
    useMantineReactTable,
    6
    type MRT_ColumnDef,
    7
    } from 'mantine-react-table';
    8
    import { data, type Person } from './makeData';
    9
    10
    const Example = () => {
    11
    const averageSalary = useMemo(
    12
    () => data.reduce((acc, curr) => acc + curr.salary, 0) / data.length,
    13
    [],
    14
    );
    15
    16
    const maxAge = useMemo(
    17
    () => data.reduce((acc, curr) => Math.max(acc, curr.age), 0),
    18
    [],
    19
    );
    20
    21
    const columns = useMemo<MRT_ColumnDef<Person>[]>(
    22
    () => [
    23
    {
    24
    header: 'First Name',
    25
    accessorKey: 'firstName',
    26
    enableGrouping: false, //do not let this column be grouped
    27
    },
    28
    {
    29
    header: 'Last Name',
    30
    accessorKey: 'lastName',
    31
    },
    32
    {
    33
    header: 'Age',
    34
    accessorKey: 'age',
    35
    aggregationFn: 'max', //show the max age in the group (lots of pre-built aggregationFns to choose from)
    36
    //required to render an aggregated cell
    37
    AggregatedCell: ({ cell, table }) => (
    38
    <>
    39
    Oldest by{' '}
    40
    {table.getColumn(cell.row.groupingColumnId ?? '').columnDef.header}:{' '}
    41
    <Box
    42
    sx={{ color: 'skyblue', display: 'inline', fontWeight: 'bold' }}
    43
    >
    44
    {cell.getValue<number>()}
    45
    </Box>
    46
    </>
    47
    ),
    48
    Footer: () => (
    49
    <Stack>
    50
    Max Age:
    51
    <Box color="orange">{Math.round(maxAge)}</Box>
    52
    </Stack>
    53
    ),
    54
    },
    55
    {
    56
    header: 'Gender',
    57
    accessorKey: 'gender',
    58
    //optionally, customize the cell render when this column is grouped. Make the text blue and pluralize the word
    59
    GroupedCell: ({ cell, row }) => (
    60
    <Box sx={{ color: 'skyblue' }}>
    61
    <strong>{cell.getValue<string>()}s </strong> ({row.subRows?.length})
    62
    </Box>
    63
    ),
    64
    },
    65
    {
    66
    header: 'State',
    67
    accessorKey: 'state',
    68
    },
    69
    {
    70
    header: 'Salary',
    71
    accessorKey: 'salary',
    72
    aggregationFn: 'mean',
    73
    //required to render an aggregated cell, show the average salary in the group
    74
    AggregatedCell: ({ cell, table }) => (
    75
    <>
    76
    Average by{' '}
    77
    {table.getColumn(cell.row.groupingColumnId ?? '').columnDef.header}:{' '}
    78
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    79
    {cell.getValue<number>()?.toLocaleString?.('en-US', {
    80
    style: 'currency',
    81
    currency: 'USD',
    82
    minimumFractionDigits: 0,
    83
    maximumFractionDigits: 0,
    84
    })}
    85
    </Box>
    86
    </>
    87
    ),
    88
    //customize normal cell render on normal non-aggregated rows
    89
    Cell: ({ cell }) => (
    90
    <>
    91
    {cell.getValue<number>()?.toLocaleString?.('en-US', {
    92
    style: 'currency',
    93
    currency: 'USD',
    94
    minimumFractionDigits: 0,
    95
    maximumFractionDigits: 0,
    96
    })}
    97
    </>
    98
    ),
    99
    Footer: () => (
    100
    <Stack>
    101
    Average Salary:
    102
    <Box color="orange">
    103
    {averageSalary?.toLocaleString?.('en-US', {
    104
    style: 'currency',
    105
    currency: 'USD',
    106
    minimumFractionDigits: 0,
    107
    maximumFractionDigits: 0,
    108
    })}
    109
    </Box>
    110
    </Stack>
    111
    ),
    112
    },
    113
    ],
    114
    [averageSalary, maxAge],
    115
    );
    116
    117
    const table = useMantineReactTable({
    118
    columns,
    119
    data,
    120
    enableColumnResizing: true,
    121
    enableGrouping: true,
    122
    enableStickyHeader: true,
    123
    enableStickyFooter: true,
    124
    initialState: {
    125
    density: 'xs',
    126
    expanded: true,
    127
    grouping: ['state'],
    128
    pagination: { pageIndex: 0, pageSize: 20 },
    129
    sorting: [{ id: 'state', desc: false }],
    130
    },
    131
    mantineToolbarAlertBannerBadgeProps: { color: 'blue', variant: 'outline' },
    132
    mantineTableContainerProps: { sx: { maxHeight: 700 } },
    133
    });
    134
    135
    return <MantineReactTable table={table} />;
    136
    };
    137
    138
    export default Example;
    1
    import { useMemo } from 'react';
    2
    import { Box, Stack } from '@mantine/core';
    3
    import { MantineReactTable, useMantineReactTable } from 'mantine-react-table';
    4
    import { data } from './makeData';
    5
    6
    const Example = () => {
    7
    const averageSalary = useMemo(
    8
    () => data.reduce((acc, curr) => acc + curr.salary, 0) / data.length,
    9
    [],
    10
    );
    11
    12
    const maxAge = useMemo(
    13
    () => data.reduce((acc, curr) => Math.max(acc, curr.age), 0),
    14
    [],
    15
    );
    16
    17
    const columns = useMemo(
    18
    () => [
    19
    {
    20
    header: 'First Name',
    21
    accessorKey: 'firstName',
    22
    enableGrouping: false, //do not let this column be grouped
    23
    },
    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 cell
    33
    AggregatedCell: ({ cell, table }) => (
    34
    <>
    35
    Oldest by{' '}
    36
    {table.getColumn(cell.row.groupingColumnId ?? '').columnDef.header}:{' '}
    37
    <Box
    38
    sx={{ color: 'skyblue', display: 'inline', fontWeight: 'bold' }}
    39
    >
    40
    {cell.getValue()}
    41
    </Box>
    42
    </>
    43
    ),
    44
    Footer: () => (
    45
    <Stack>
    46
    Max Age:
    47
    <Box color="orange">{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 word
    55
    GroupedCell: ({ cell, row }) => (
    56
    <Box sx={{ color: 'skyblue' }}>
    57
    <strong>{cell.getValue()}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 group
    70
    AggregatedCell: ({ cell, table }) => (
    71
    <>
    72
    Average by{' '}
    73
    {table.getColumn(cell.row.groupingColumnId ?? '').columnDef.header}:{' '}
    74
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    75
    {cell.getValue()?.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 rows
    85
    Cell: ({ cell }) => (
    86
    <>
    87
    {cell.getValue()?.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="orange">
    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
    );
    112
    113
    const table = useMantineReactTable({
    114
    columns,
    115
    data,
    116
    enableColumnResizing: true,
    117
    enableGrouping: true,
    118
    enableStickyHeader: true,
    119
    enableStickyFooter: true,
    120
    initialState: {
    121
    density: 'xs',
    122
    expanded: true,
    123
    grouping: ['state'],
    124
    pagination: { pageIndex: 0, pageSize: 20 },
    125
    sorting: [{ id: 'state', desc: false }],
    126
    },
    127
    mantineToolbarAlertBannerBadgeProps: { color: 'blue', variant: 'outline' },
    128
    mantineTableContainerProps: { sx: { maxHeight: 700 } },
    129
    });
    130
    131
    return <MantineReactTable table={table} />;
    132
    };
    133
    134
    export default Example;

    Multiple Aggregations Per column

    You may want to calculate more than one aggregation per column. If so, you can specify an array of aggregationFns, and then reference the aggregation results from an array in the AggregatedCell render option.
    const columns = [
    {
    header: 'Salary',
    accessorKey: 'salary',
    aggregationFn: ['count', 'mean'], //multiple aggregation functions
    AggregatedCell: ({ cell, table }) => (
    <div>
    {/*get the count from the first aggregation*/}
    <div>Count: {cell.getValue()[0]}</div>
    {/*get the average from the second aggregation*/}
    <div>Average Salary: {cell.getValue()[1]}</div>
    </div>
    ),
    },
    ];
    Alabama (3)Count:
    7
    Average:
    $43,375
    Median:
    $56,146
    Min:
    $10,645
    Max:
    $71,238
    Female (4)Count:
    4
    Average:
    $40,264
    Median:
    $43,339
    Min:
    $10,645
    Max:
    $63,733
    ThadWiegand$56,146
    ReinholdReichel$30,531
    LurlineKoepp$10,645
    KodyBraun$63,733
    Male (2)Count:
    2
    Average:
    $41,915
    Median:
    $41,915
    Min:
    $12,591
    Max:
    $71,238
    AliviaLedner$12,591
    DanykaGleason$71,238
    Nonbinary (1)Count:
    1
    Average:
    $58,743
    Median:
    $58,743
    Min:
    $58,743
    Max:
    $58,743
    LionelHartmann$58,743
    Alaska (2)Count:
    8
    Average:
    $68,901
    Median:
    $75,746
    Min:
    $35,159
    Max:
    $98,252
    Male (4)Count:
    4
    Average:
    $65,414
    Median:
    $67,396
    Min:
    $45,801
    Max:
    $81,062
    EloisaKohler$45,801
    KianHand$81,062
    MichaleCollier$75,197
    EldridgeStroman$59,594
    Female (4)Count:
    4
    Average:
    $72,388
    Median:
    $78,070
    Min:
    $35,159
    Max:
    $98,252
    LoyceSchmidt$76,295
    AlveraBalistreri$79,844
    1-20 of 342
    1
    import { useMemo } from 'react';
    2
    import { Box } from '@mantine/core';
    3
    import { MantineReactTable, type MRT_ColumnDef } from 'mantine-react-table';
    4
    import { data, type Person } from './makeData';
    5
    6
    const localeStringOptions = {
    7
    style: 'currency',
    8
    currency: 'USD',
    9
    minimumFractionDigits: 0,
    10
    maximumFractionDigits: 0,
    11
    };
    12
    13
    const Example = () => {
    14
    const columns = useMemo<MRT_ColumnDef<Person>[]>(
    15
    () => [
    16
    {
    17
    header: 'First Name',
    18
    accessorKey: 'firstName',
    19
    },
    20
    {
    21
    header: 'Last Name',
    22
    accessorKey: 'lastName',
    23
    },
    24
    {
    25
    header: 'Gender',
    26
    accessorKey: 'gender',
    27
    },
    28
    {
    29
    header: 'State',
    30
    accessorKey: 'state',
    31
    },
    32
    {
    33
    header: 'Salary',
    34
    accessorKey: 'salary',
    35
    aggregationFn: ['count', 'mean', 'median', 'min', 'max'],
    36
    //required to render an aggregated cell, show the average salary in the group
    37
    AggregatedCell: ({ cell }) => (
    38
    <>
    39
    Count:{' '}
    40
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    41
    {cell.getValue<Array<number>>()?.[0]}
    42
    </Box>
    43
    Average:{' '}
    44
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    45
    {cell
    46
    .getValue<Array<number>>()?.[1]
    47
    ?.toLocaleString?.('en-US', localeStringOptions)}
    48
    </Box>
    49
    Median:{' '}
    50
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    51
    {cell
    52
    .getValue<Array<number>>()?.[2]
    53
    ?.toLocaleString?.('en-US', localeStringOptions)}
    54
    </Box>
    55
    Min:{' '}
    56
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    57
    {cell
    58
    .getValue<Array<number>>()?.[3]
    59
    ?.toLocaleString?.('en-US', localeStringOptions)}
    60
    </Box>
    61
    Max:{' '}
    62
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    63
    {cell
    64
    .getValue<Array<number>>()?.[4]
    65
    ?.toLocaleString?.('en-US', localeStringOptions)}
    66
    </Box>
    67
    </>
    68
    ),
    69
    //customize normal cell render on normal non-aggregated rows
    70
    Cell: ({ cell }) => (
    71
    <>
    72
    {cell
    73
    .getValue<number>()
    74
    ?.toLocaleString?.('en-US', localeStringOptions)}
    75
    </>
    76
    ),
    77
    },
    78
    ],
    79
    [],
    80
    );
    81
    82
    return (
    83
    <MantineReactTable
    84
    columns={columns}
    85
    data={data}
    86
    enableGrouping
    87
    enableStickyHeader
    88
    initialState={{
    89
    density: 'xs',
    90
    expanded: true, //expand all groups by default
    91
    grouping: ['state', 'gender'], //an array of columns to group by by default (can be multiple)
    92
    pagination: { pageIndex: 0, pageSize: 20 },
    93
    sorting: [{ id: 'state', desc: false }], //sort by state by default
    94
    }}
    95
    mantineToolbarAlertBannerBadgeProps={{ color: 'primary' }}
    96
    mantineTableContainerProps={{ sx: { maxHeight: 700 } }}
    97
    />
    98
    );
    99
    };
    100
    101
    export default Example;
    1
    import { useMemo } from 'react';
    2
    import { Box } from '@mantine/core';
    3
    import { MantineReactTable } from 'mantine-react-table';
    4
    import { data } from './makeData';
    5
    6
    const localeStringOptions = {
    7
    style: 'currency',
    8
    currency: 'USD',
    9
    minimumFractionDigits: 0,
    10
    maximumFractionDigits: 0,
    11
    };
    12
    13
    const Example = () => {
    14
    const columns = useMemo(
    15
    () => [
    16
    {
    17
    header: 'First Name',
    18
    accessorKey: 'firstName',
    19
    },
    20
    {
    21
    header: 'Last Name',
    22
    accessorKey: 'lastName',
    23
    },
    24
    {
    25
    header: 'Gender',
    26
    accessorKey: 'gender',
    27
    },
    28
    {
    29
    header: 'State',
    30
    accessorKey: 'state',
    31
    },
    32
    {
    33
    header: 'Salary',
    34
    accessorKey: 'salary',
    35
    aggregationFn: ['count', 'mean', 'median', 'min', 'max'],
    36
    //required to render an aggregated cell, show the average salary in the group
    37
    AggregatedCell: ({ cell }) => (
    38
    <>
    39
    Count:{' '}
    40
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    41
    {cell.getValue()?.[0]}
    42
    </Box>
    43
    Average:{' '}
    44
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    45
    {cell
    46
    .getValue()?.[1]
    47
    ?.toLocaleString?.('en-US', localeStringOptions)}
    48
    </Box>
    49
    Median:{' '}
    50
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    51
    {cell
    52
    .getValue()?.[2]
    53
    ?.toLocaleString?.('en-US', localeStringOptions)}
    54
    </Box>
    55
    Min:{' '}
    56
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    57
    {cell
    58
    .getValue()?.[3]
    59
    ?.toLocaleString?.('en-US', localeStringOptions)}
    60
    </Box>
    61
    Max:{' '}
    62
    <Box sx={{ color: 'green', fontWeight: 'bold' }}>
    63
    {cell
    64
    .getValue()?.[4]
    65
    ?.toLocaleString?.('en-US', localeStringOptions)}
    66
    </Box>
    67
    </>
    68
    ),
    69
    //customize normal cell render on normal non-aggregated rows
    70
    Cell: ({ cell }) => (
    71
    <>{cell.getValue()?.toLocaleString?.('en-US', localeStringOptions)}</>
    72
    ),
    73
    },
    74
    ],
    75
    [],
    76
    );
    77
    78
    return (
    79
    <MantineReactTable
    80
    columns={columns}
    81
    data={data}
    82
    enableGrouping
    83
    enableStickyHeader
    84
    initialState={{
    85
    density: 'xs',
    86
    expanded: true, //expand all groups by default
    87
    grouping: ['state', 'gender'], //an array of columns to group by by default (can be multiple)
    88
    pagination: { pageIndex: 0, pageSize: 20 },
    89
    sorting: [{ id: 'state', desc: false }], //sort by state by default
    90
    }}
    91
    mantineToolbarAlertBannerBadgeProps={{ color: 'primary' }}
    92
    mantineTableContainerProps={{ sx: { maxHeight: 700 } }}
    93
    />
    94
    );
    95
    };
    96
    97
    export default Example;

    Manual Grouping

    Manual Grouping means that the data that you pass to the table is already grouped and aggregated, and you do not want Mantine React Table to do any of the grouping or aggregation for you. This is useful if you are using a backend API to do the grouping and aggregation for you, and you just want to display the results. However, you will need to put your data in the specific format that the expanding features understand.
    You can help make these docs better! PRs are Welcome
    Using Material-UI instead of Mantine?
    Check out Material React Table