MRT logoMantine React Table

On This Page

    Row Ordering (DnD) Feature Guide

    Mantine React Table has exposes all the APIs necessary to enable rich row drag and drop features that you can easily build to meet your needs. This includes the ability to reorder rows, drag rows to other tables, or drag rows to other UI in your application.
    This is not the Sorting Guide which is a different feature.

    Relevant Table Options

    1
    boolean
    2
    boolean
    3
    ActionIconProps | ({ row, table }) => ActionIconProps
    Mantine ActionIcon Docs
    4
    OnChangeFn<MRT_Row<TData> | null>
    5
    OnChangeFn<MRT_Row<TData> | null>

    Relevant State

    1
    MRT_Row | null
    2
    MRT_Row | null

    Enable Row Ordering

    A common use for row drag and drop is to allow users to reorder rows in a table. This can be done by setting the enableRowOrdering table option to true, and then setting up an onDragEnd event handler on the mantineRowDragHandleProps table option.
    const table = useMantineReactTable({
    columns,
    data,
    enableRowOrdering: true,
    enableSorting: false, //usually you do not want to sort when re-ordering
    mantineRowDragHandleProps: {
    onDragEnd: (event, data) => {
    //data re-ordering logic here
    },
    },
    });
    DylanMurrayEast Daphne
    RaquelKohlerColumbus
    ErvinReingerSouth Linda
    BrittanyMcCulloughLincoln
    BransonFramiCharleston
    1-5 of 5
    1
    import { useMemo, useState } from 'react';
    2
    import { MantineReactTable, MRT_ColumnDef, MRT_Row } from 'mantine-react-table';
    3
    import { data as initData, Person } from './makeData';
    4
    5
    const Example = () => {
    6
    const columns = useMemo<MRT_ColumnDef<Person>[]>(
    7
    () => [
    8
    {
    9
    accessorKey: 'firstName',
    10
    header: 'First Name',
    11
    },
    12
    {
    13
    accessorKey: 'lastName',
    14
    header: 'Last Name',
    15
    },
    16
    {
    17
    accessorKey: 'city',
    18
    header: 'City',
    19
    },
    20
    ],
    21
    [],
    22
    );
    23
    24
    const [data, setData] = useState(() => initData);
    25
    26
    return (
    27
    <MantineReactTable
    28
    autoResetPageIndex={false}
    29
    columns={columns}
    30
    data={data}
    31
    enableRowOrdering
    32
    enableSorting={false}
    33
    mantineRowDragHandleProps={({ table }) => ({
    34
    onDragEnd: () => {
    35
    const { draggingRow, hoveredRow } = table.getState();
    36
    if (hoveredRow && draggingRow) {
    37
    data.splice(
    38
    (hoveredRow as MRT_Row<Person>).index,
    39
    0,
    40
    data.splice(draggingRow.index, 1)[0],
    41
    );
    42
    setData([...data]);
    43
    }
    44
    },
    45
    })}
    46
    />
    47
    );
    48
    };
    49
    50
    export default Example;
    1
    import { useMemo, useState } from 'react';
    2
    import { MantineReactTable } from 'mantine-react-table';
    3
    import { data as initData } from './makeData';
    4
    5
    const Example = () => {
    6
    const columns = useMemo(
    7
    () => [
    8
    {
    9
    accessorKey: 'firstName',
    10
    header: 'First Name',
    11
    },
    12
    {
    13
    accessorKey: 'lastName',
    14
    header: 'Last Name',
    15
    },
    16
    {
    17
    accessorKey: 'city',
    18
    header: 'City',
    19
    },
    20
    ],
    21
    [],
    22
    );
    23
    24
    const [data, setData] = useState(() => initData);
    25
    26
    return (
    27
    <MantineReactTable
    28
    autoResetPageIndex={false}
    29
    columns={columns}
    30
    data={data}
    31
    enableRowOrdering
    32
    enableSorting={false}
    33
    mantineRowDragHandleProps={({ table }) => ({
    34
    onDragEnd: () => {
    35
    const { draggingRow, hoveredRow } = table.getState();
    36
    if (hoveredRow && draggingRow) {
    37
    data.splice(
    38
    hoveredRow.index,
    39
    0,
    40
    data.splice(draggingRow.index, 1)[0],
    41
    );
    42
    setData([...data]);
    43
    }
    44
    },
    45
    })}
    46
    />
    47
    );
    48
    };
    49
    50
    export default Example;

    Drag and Drop Rows to Other UI or Tables

    The Drag and Drop features are not limited to just internally within the same table. You can use them to drag rows to other UI in your application, or even to other tables. This can be done by setting the enableRowDragging table option to true, and then setting up an onDragEnd event handler on the mantineRowDragHandleProps table option to perform whatever logic you want to happen when a row is dropped.

    Nice List

    DylanMurrayEast Daphne
    RaquelKohlerColumbus
    ErvinReingerSouth Linda
    1-3 of 3

    Naughty List

    BrittanyMcCulloughLincoln
    BransonFramiCharleston
    1-2 of 2
    1
    import { useMemo, useState } from 'react';
    2
    import {
    3
    MantineReactTable,
    4
    MRT_TableOptions,
    5
    MRT_ColumnDef,
    6
    MRT_Row,
    7
    } from 'mantine-react-table';
    8
    import { Box, Title } from '@mantine/core';
    9
    import { data, type Person } from './makeData';
    10
    11
    const Example = () => {
    12
    const columns = useMemo<MRT_ColumnDef<Person>[]>(
    13
    () => [
    14
    {
    15
    accessorKey: 'firstName',
    16
    header: 'First Name',
    17
    },
    18
    {
    19
    accessorKey: 'lastName',
    20
    header: 'Last Name',
    21
    },
    22
    {
    23
    accessorKey: 'city',
    24
    header: 'City',
    25
    },
    26
    ],
    27
    [],
    28
    );
    29
    30
    const [data1, setData1] = useState<Person[]>(() => data.slice(0, 3));
    31
    const [data2, setData2] = useState<Person[]>(() => data.slice(3, 5));
    32
    33
    const [draggingRow, setDraggingRow] = useState<MRT_Row<Person> | null>(null);
    34
    const [hoveredTable, setHoveredTable] = useState<string | null>(null);
    35
    36
    const commonTableProps: Partial<MRT_TableOptions<Person>> & {
    37
    columns: MRT_ColumnDef<Person>[];
    38
    } = {
    39
    columns,
    40
    enableRowDragging: true,
    41
    enableFullScreenToggle: false,
    42
    mantineTableContainerProps: {
    43
    sx: {
    44
    minHeight: '320px',
    45
    },
    46
    },
    47
    onDraggingRowChange: setDraggingRow,
    48
    state: { draggingRow },
    49
    };
    50
    51
    return (
    52
    <Box
    53
    sx={{
    54
    display: 'grid',
    55
    gridTemplateColumns: '1fr 1fr',
    56
    gap: '16px',
    57
    overflow: 'auto',
    58
    padding: '4px',
    59
    '@media (max-width: 960px)': {
    60
    gridTemplateColumns: 'auto',
    61
    },
    62
    }}
    63
    >
    64
    <MantineReactTable
    65
    {...commonTableProps}
    66
    data={data1}
    67
    getRowId={(originalRow) => `table-1-${originalRow.firstName}`}
    68
    mantineRowDragHandleProps={{
    69
    onDragEnd: () => {
    70
    if (hoveredTable === 'table-2') {
    71
    setData2((data2) => [...data2, draggingRow!.original]);
    72
    setData1((data1) =>
    73
    data1.filter((d) => d !== draggingRow!.original),
    74
    );
    75
    }
    76
    setHoveredTable(null);
    77
    },
    78
    }}
    79
    mantinePaperProps={{
    80
    onDragEnter: () => setHoveredTable('table-1'),
    81
    sx: {
    82
    outline: hoveredTable === 'table-1' ? '2px dashed pink' : undefined,
    83
    },
    84
    }}
    85
    renderTopToolbarCustomActions={() => (
    86
    <Title color="green" order={4}>
    87
    Nice List
    88
    </Title>
    89
    )}
    90
    />
    91
    <MantineReactTable
    92
    {...commonTableProps}
    93
    data={data2}
    94
    defaultColumn={{
    95
    size: 100,
    96
    }}
    97
    getRowId={(originalRow) => `table-2-${originalRow.firstName}`}
    98
    mantineRowDragHandleProps={{
    99
    onDragEnd: () => {
    100
    if (hoveredTable === 'table-1') {
    101
    setData1((data1) => [...data1, draggingRow!.original]);
    102
    setData2((data2) =>
    103
    data2.filter((d) => d !== draggingRow!.original),
    104
    );
    105
    }
    106
    setHoveredTable(null);
    107
    },
    108
    }}
    109
    mantinePaperProps={{
    110
    onDragEnter: () => setHoveredTable('table-2'),
    111
    sx: {
    112
    outline: hoveredTable === 'table-2' ? '2px dashed pink' : undefined,
    113
    },
    114
    }}
    115
    renderTopToolbarCustomActions={() => (
    116
    <Title color="red" order={4}>
    117
    Naughty List
    118
    </Title>
    119
    )}
    120
    />
    121
    </Box>
    122
    );
    123
    };
    124
    125
    export default Example;
    1
    import { useMemo, useState } from 'react';
    2
    import { MantineReactTable } from 'mantine-react-table';
    3
    import { Box, Title } from '@mantine/core';
    4
    import { data } from './makeData';
    5
    6
    const Example = () => {
    7
    const columns = useMemo(
    8
    () => [
    9
    {
    10
    accessorKey: 'firstName',
    11
    header: 'First Name',
    12
    },
    13
    {
    14
    accessorKey: 'lastName',
    15
    header: 'Last Name',
    16
    },
    17
    {
    18
    accessorKey: 'city',
    19
    header: 'City',
    20
    },
    21
    ],
    22
    [],
    23
    );
    24
    25
    const [data1, setData1] = useState(() => data.slice(0, 3));
    26
    const [data2, setData2] = useState(() => data.slice(3, 5));
    27
    28
    const [draggingRow, setDraggingRow] = useState(null);
    29
    const [hoveredTable, setHoveredTable] = useState(null);
    30
    31
    const commonTableProps = {
    32
    columns,
    33
    enableRowDragging: true,
    34
    enableFullScreenToggle: false,
    35
    mantineTableContainerProps: {
    36
    sx: {
    37
    minHeight: '320px',
    38
    },
    39
    },
    40
    onDraggingRowChange: setDraggingRow,
    41
    state: { draggingRow },
    42
    };
    43
    44
    return (
    45
    <Box
    46
    sx={{
    47
    display: 'grid',
    48
    gridTemplateColumns: '1fr 1fr',
    49
    gap: '16px',
    50
    overflow: 'auto',
    51
    padding: '4px',
    52
    '@media (max-width: 960px)': {
    53
    gridTemplateColumns: 'auto',
    54
    },
    55
    }}
    56
    >
    57
    <MantineReactTable
    58
    {...commonTableProps}
    59
    data={data1}
    60
    defaultColumn={{
    61
    size: 100,
    62
    }}
    63
    getRowId={(originalRow) => `table-1-${originalRow.firstName}`}
    64
    mantineRowDragHandleProps={{
    65
    onDragEnd: () => {
    66
    if (hoveredTable === 'table-2') {
    67
    setData2((data2) => [...data2, draggingRow.original]);
    68
    setData1((data1) =>
    69
    data1.filter((d) => d !== draggingRow.original),
    70
    );
    71
    }
    72
    setHoveredTable(null);
    73
    },
    74
    }}
    75
    mantinePaperProps={{
    76
    onDragEnter: () => setHoveredTable('table-1'),
    77
    sx: {
    78
    outline: hoveredTable === 'table-1' ? '2px dashed pink' : undefined,
    79
    },
    80
    }}
    81
    renderTopToolbarCustomActions={() => (
    82
    <Title color="green" order={4}>
    83
    Nice List
    84
    </Title>
    85
    )}
    86
    />
    87
    <MantineReactTable
    88
    {...commonTableProps}
    89
    data={data2}
    90
    getRowId={(originalRow) => `table-2-${originalRow.firstName}`}
    91
    mantineRowDragHandleProps={{
    92
    onDragEnd: () => {
    93
    if (hoveredTable === 'table-1') {
    94
    setData1((data1) => [...data1, draggingRow.original]);
    95
    setData2((data2) =>
    96
    data2.filter((d) => d !== draggingRow.original),
    97
    );
    98
    }
    99
    setHoveredTable(null);
    100
    },
    101
    }}
    102
    mantinePaperProps={{
    103
    onDragEnter: () => setHoveredTable('table-2'),
    104
    sx: {
    105
    outline: hoveredTable === 'table-2' ? '2px dashed pink' : undefined,
    106
    },
    107
    }}
    108
    renderTopToolbarCustomActions={() => (
    109
    <Title color="red" order={4}>
    110
    Naughty List
    111
    </Title>
    112
    )}
    113
    />
    114
    </Box>
    115
    );
    116
    };
    117
    118
    export default Example;
    View Extra Storybook Examples
    Note: Drag and Drop is not currently supported on mobile touch devices.
    You can help make these docs better! PRs are Welcome
    Using Material-UI instead of Mantine?
    Check out Material React Table