MRT logoMantine React Table

On This Page

    Data (Accessor) Columns

    Data columns are used to display data and are the default columns that are created when you create a column with an accessorKey or accessorFn.
    The table can perform processing on the data of a data column, such as sorting, filtering, grouping, etc.
    The other type of column that you can make is a display column, which you can learn more about in the next section.

    Accessors (Connect a column to data)

    Each column definition must have at least an accessorKey (or a combination of an id and accessorFn) and a header property. The accessorKey/accessorFn property is the key that will be used to join the data from the data keys. The header property is used to display the column header, but is also used in other places in the table.

    Method 1 - Using an accessorKey (Recommended)

    The simplest and most common way to define a column is to use the accessorKey property. The accessorKey property is the key that will be used to join the data from the data keys.
    The accessorKey must match one of the keys in your data, or else no data will show up in the column. The accessorKey also supports dot notation, so you can access nested data.
    By default, the accessorKey will double as the id for the column, but if you need the id of the column to be different than the accessorKey, you can use the id property in addition.
    const columns = useMemo<MRT_ColumnDef<Customer>[]>( //TS helps with the autocomplete while writing columns
    () => [
    {
    accessorKey: 'username', //normal recommended usage of an accessorKey
    header: 'Username',
    },
    {
    accessorKey: 'name.firstName', //example of dot notation used to access nested data
    header: 'First Name',
    },
    {
    accessorKey: 'name.lastName', //example of dot notation used to access nested data
    header: 'Last Name',
    },
    {
    accessorKey: 'customerAge',
    id: 'age' //id overridden, usually not necessary to do this, but can be helpful
    header: 'Age',
    },
    ],
    [],
    );

    Method 2 - Using an accessorFn and id

    You can alternatively use the accessorFn property. Here are at least three ways you can use it.
    In each case, the id property is now required since there is no accessorKey for MRT to derive it from.
    const columns = useMemo(
    () => [
    {
    //simple accessorFn that works the same way as an `accessorKey`
    accessorFn: (row) => row.username,
    id: 'username',
    header: 'Username',
    },
    {
    //accessorFn function that combines multiple data together
    accessorFn: (row) => `${row.firstName} ${row.lastName}`,
    id: 'name',
    header: 'Name',
    },
    {
    //accessorFn used to access nested data, though you could just use dot notation in an accessorKey
    accessorFn: (row) => row.personalInfo.age,
    id: 'age',
    header: 'Age',
    },
    ],
    [],
    );

    Custom Header Render

    If you want to pass in custom JSX to render the header, you can pass in a Header option in addition to the header string property.
    The header (lowercase) property is still required and still must only be a string because it is used within multiple components in the table and has string manipulation methods performed on it.
    const columns = useMemo(
    () => [
    {
    accessorKey: 'name',
    header: 'Name',
    Header: ({ column }) => (
    <i style={{ color: 'red' }}>{column.columnDef.header}</i>
    ), //arrow function
    },
    {
    accessorKey: 'age',
    header: 'Age',
    Header: <i style={{ color: 'red' }}>Age</i>, //plain jsx with no function
    },
    ],
    [],
    );

    Custom Cell Render

    Similarly, the data cells in a column can have a custom JSX render with the Cell option.
    const columns = useMemo(
    () => [
    {
    accessorKey: 'salary',
    header: 'Salary',
    Cell: ({ cell }) => (
    <span>${cell.getValue<number>().toLocaleString()}</span>
    ),
    },
    {
    accessorKey: 'profileImage',
    header: 'Profile Image',
    Cell: ({ cell }) => <img src={cell.getValue<string>()} />,
    },
    ],
    [],
    );
    If you want to pass in custom JSX to render the footer, you can pass in a Footer option. If no custom markup is needed, you can just use the footer string property.
    The footer cells can be a good place to put totals or other summary information.
    const columns = useMemo(
    () => [
    {
    accessorKey: 'name',
    header: 'Name',
    footer: 'Name', //simple string header
    },
    {
    accessorKey: 'age',
    header: 'Age',
    //Custom footer markup for a aggregation calculation
    Footer: () => (
    <Stack>
    Max Age:
    <Box color="orange">{Math.round(maxAge)}</Box>
    </Stack>
    ),
    },
    ],
    [],
    );
    See the Customize Components Guide for more ways to style and customize header and cell components.

    Enable or Disable Features Per Column

    In the same way that you can pass props to the main <MantineReactTable /> component to enable or disable features, you can also specify options on the column definitions to enable or disable features on a per-column basis.
    const columns = useMemo(
    () => [
    {
    accessorKey: 'salary',
    header: 'Salary',
    enableClickToCopy: true, //enable click to copy on this column
    },
    {
    accessorKey: 'profileImage',
    header: 'Profile Image',
    enableSorting: false, //disable sorting on this column
    },
    ],
    [],
    );
    See all the column options you can use in the Column Options API Reference.

    Set Column Widths

    This topic is covered in detail in the Column Resizing Guide, but here is a brief overview.
    Setting a CSS (sx or style) width prop will NOT work. Mantine React Table (or, more accurately, TanStack Table) will keep track and set the widths of each column internally.
    You CAN, however, change the default width of any column by setting its size option on the column definition. minSize and maxSize are also available to set the minimum and maximum width of the column during resizing.
    const columns = [
    {
    accessorKey: 'id',
    header: 'ID',
    size: 50, //small column
    },
    {
    accessorKey: 'username',
    header: 'Username',
    minSize: 100, //min size enforced during resizing
    maxSize: 200, //max size enforced during resizing
    size: 180, //medium column
    },
    {
    accessorKey: 'email',
    header: 'Email',
    size: 300, //large column
    },
    ];
    However, the column sizes might not change as much as you would expect. This is because the browser treats <th> and <td> elements differently with in a <table> element by default.
    You can improve this slightly by changing the table layout to fixed instead of the default auto in the mantineTableProps.
    const table = useMantineReactTable({
    mantineTableProps: {
    sx: {
    tableLayout: 'fixed',
    },
    },
    });
    The columns will still try to increase their width to take up the full width of the table, but the columns that do have a defined size will have their width respected more.
    To learn more about how table-layout fixed vs auto works, we recommend reading this blog post by CSS-Tricks.

    Disable Column Growing

    By default, columns grow to fill the width of the table. However, you can disable this behavior by setting the flexGrow css for the table head and body cells to 0 when the layoutMode prop is also set to "grid". This is covered in more detail in the Column Resizing Guide.

    Set Column Alignment

    By default, all columns are left-aligned. You can change the alignment of a column by setting the align option to either "center", "right", or "justify" in the mantineTableHeadCellProps and mantineTableBodyCellProps props/column options.
    const columns = [
    {
    accessorKey: 'id',
    header: 'ID',
    //right align the header and body cells
    mantineTableHeadCellProps: {
    align: 'right',
    },
    mantineTableBodyCellProps: {
    align: 'right',
    },
    },
    {
    accessorKey: 'username',
    header: 'Username',
    //center align the header and body cells
    mantineTableHeadCellProps: {
    align: 'center',
    },
    mantineTableBodyCellProps: {
    align: 'center',
    },
    },
    ];
    HomerSimpson39$53,000.00
    MargeSimpson38$60,000.00
    BartSimpson10$46,000.00
    LisaSimpson8$120,883.00
    MaggieSimpson1$22.00
    1-5 of 5
    1
    import { useMemo } from 'react';
    2
    import { MantineReactTable, type MRT_ColumnDef } from 'mantine-react-table';
    3
    import { data, type Person } from './makeData';
    4
    5
    const Example = () => {
    6
    const columns = useMemo<MRT_ColumnDef<Person>[]>(
    7
    () => [
    8
    {
    9
    accessorKey: 'firstName',
    10
    header: 'First Name',
    11
    size: 100,
    12
    mantineTableHeadCellProps: {
    13
    align: 'center',
    14
    },
    15
    mantineTableBodyCellProps: {
    16
    align: 'center',
    17
    },
    18
    },
    19
    {
    20
    accessorKey: 'lastName',
    21
    header: 'Last Name',
    22
    size: 100,
    23
    mantineTableHeadCellProps: {
    24
    align: 'center',
    25
    },
    26
    mantineTableBodyCellProps: {
    27
    align: 'center',
    28
    },
    29
    },
    30
    {
    31
    accessorKey: 'age',
    32
    header: 'Age',
    33
    mantineTableHeadCellProps: {
    34
    align: 'right',
    35
    },
    36
    mantineTableBodyCellProps: {
    37
    align: 'right',
    38
    },
    39
    },
    40
    {
    41
    accessorKey: 'salary',
    42
    header: 'Salary',
    43
    mantineTableHeadCellProps: {
    44
    align: 'right',
    45
    },
    46
    mantineTableBodyCellProps: {
    47
    align: 'right',
    48
    },
    49
    Cell: ({ cell }) =>
    50
    cell
    51
    .getValue<number>()
    52
    .toLocaleString('en-US', { style: 'currency', currency: 'USD' }),
    53
    },
    54
    ],
    55
    [],
    56
    );
    57
    58
    return <MantineReactTable columns={columns} data={data} />;
    59
    };
    60
    61
    export default Example;
    1
    import { useMemo } from 'react';
    2
    import { MantineReactTable } from 'mantine-react-table';
    3
    import { data } from './makeData';
    4
    5
    const Example = () => {
    6
    const columns = useMemo(
    7
    () => [
    8
    {
    9
    accessorKey: 'firstName',
    10
    header: 'First Name',
    11
    size: 100,
    12
    mantineTableHeadCellProps: {
    13
    align: 'center',
    14
    },
    15
    mantineTableBodyCellProps: {
    16
    align: 'center',
    17
    },
    18
    },
    19
    {
    20
    accessorKey: 'lastName',
    21
    header: 'Last Name',
    22
    size: 100,
    23
    mantineTableHeadCellProps: {
    24
    align: 'center',
    25
    },
    26
    mantineTableBodyCellProps: {
    27
    align: 'center',
    28
    },
    29
    },
    30
    {
    31
    accessorKey: 'age',
    32
    header: 'Age',
    33
    mantineTableHeadCellProps: {
    34
    align: 'right',
    35
    },
    36
    mantineTableBodyCellProps: {
    37
    align: 'right',
    38
    },
    39
    },
    40
    {
    41
    accessorKey: 'salary',
    42
    header: 'Salary',
    43
    mantineTableHeadCellProps: {
    44
    align: 'right',
    45
    },
    46
    mantineTableBodyCellProps: {
    47
    align: 'right',
    48
    },
    49
    Cell: ({ cell }) =>
    50
    cell
    51
    .getValue()
    52
    .toLocaleString('en-US', { style: 'currency', currency: 'USD' }),
    53
    },
    54
    ],
    55
    [],
    56
    );
    57
    58
    return <MantineReactTable columns={columns} data={data} />;
    59
    };
    60
    61
    export default Example;
    You can help make these docs better! PRs are Welcome
    Using Material-UI instead of Mantine?
    Check out Material React Table