MRT logoMaterial React Table

    Row Ordering (DnD) Feature Guide

    Material 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 Props

    1
    boolean
    2
    IconButtonProps | ({ row, table }) => IconButtonProps
    Material UI IconButton Props
    3
    OnChangeFn<MRT_Row<TData> | null>
    4
    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 prop to true, and then setting up an onDragEnd event handler on the muiTableBodyRowDragHandleProps prop.

    <MaterialReactTable
    columns={columns}
    data={data}
    enableRowOrdering
    enableSorting={false} //usually you don't want to sort when re-ordering
    muiTableBodyRowDragHandleProps={{
    onDragEnd: (event, data) => {
    //data re-ordering logic here
    },
    }}
    />

    Demo

    Open Code SandboxOpen on GitHub
    DylanMurrayEast Daphne
    RaquelKohlerColumbus
    ErvinReingerSouth Linda
    BrittanyMcCulloughLincoln
    BransonFramiCharleston

    Rows per page

    1-5 of 5

    Source Code

    1import React, { FC, useMemo, useState } from 'react';
    2import MaterialReactTable, {
    3 MRT_ColumnDef,
    4 MRT_Row,
    5} from 'material-react-table';
    6import { data as initData, Person } from './makeData';
    7
    8const Example: FC = () => {
    9 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    10 //column definitions...
    27 );
    28
    29 const [data, setData] = useState(() => initData);
    30
    31 return (
    32 <MaterialReactTable
    33 autoResetPageIndex={false}
    34 columns={columns}
    35 data={data}
    36 enableRowOrdering
    37 enableSorting={false}
    38 muiTableBodyRowDragHandleProps={({ table }) => ({
    39 onDragEnd: () => {
    40 const { draggingRow, hoveredRow } = table.getState();
    41 if (hoveredRow && draggingRow) {
    42 data.splice(
    43 (hoveredRow as MRT_Row<Person>).index,
    44 0,
    45 data.splice(draggingRow.index, 1)[0],
    46 );
    47 setData([...data]);
    48 }
    49 },
    50 })}
    51 />
    52 );
    53};
    54
    55export default Example;
    56

    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 prop to true, and then setting up an onDragEnd event handler on the muiTableBodyRowDragHandleProps prop to perform whatever logic you want to happen when a row is dropped.


    Nice List
    DylanMurrayEast Daphne
    RaquelKohlerColumbus
    ErvinReingerSouth Linda

    Rows per page

    1-3 of 3

    Naughty List
    BrittanyMcCulloughLincoln
    BransonFramiCharleston

    Rows per page

    1-2 of 2

    Source Code

    1import React, { FC, useMemo, useState } from 'react';
    2import MaterialReactTable, {
    3 MaterialReactTableProps,
    4 MRT_ColumnDef,
    5 MRT_Row,
    6} from 'material-react-table';
    7import { Box, Typography } from '@mui/material';
    8import { data, Person } from './makeData';
    9
    10const Example: FC = () => {
    11 const columns = useMemo<MRT_ColumnDef<Person>[]>(
    12 //column definitions...
    29 );
    30
    31 const [data1, setData1] = useState<Person[]>(() => data.slice(0, 3));
    32 const [data2, setData2] = useState<Person[]>(() => data.slice(3, 5));
    33
    34 const [draggingRow, setDraggingRow] = useState<MRT_Row<Person> | null>(null);
    35 const [hoveredTable, setHoveredTable] = useState<string | null>(null);
    36
    37 const commonTableProps: Partial<MaterialReactTableProps<Person>> & {
    38 columns: MRT_ColumnDef<Person>[];
    39 } = {
    40 columns,
    41 enableRowDragging: true,
    42 enableFullScreenToggle: false,
    43 muiTableContainerProps: {
    44 sx: {
    45 minHeight: '320px',
    46 },
    47 },
    48 onDraggingRowChange: setDraggingRow,
    49 state: { draggingRow },
    50 };
    51
    52 return (
    53 <Box
    54 sx={{
    55 display: 'grid',
    56 gridTemplateColumns: { xs: 'auto', lg: '1fr 1fr' },
    57 gap: '1rem',
    58 overflow: 'auto',
    59 p: '4px',
    60 }}
    61 >
    62 <MaterialReactTable
    63 {...commonTableProps}
    64 data={data1}
    65 getRowId={(originalRow) => `table-1-${originalRow.firstName}`}
    66 muiTableBodyRowDragHandleProps={{
    67 onDragEnd: () => {
    68 if (hoveredTable === 'table-2') {
    69 setData2((data2) => [...data2, draggingRow!.original]);
    70 setData1((data1) =>
    71 data1.filter((d) => d !== draggingRow!.original),
    72 );
    73 }
    74 setHoveredTable(null);
    75 },
    76 }}
    77 muiTablePaperProps={{
    78 onDragEnter: () => setHoveredTable('table-1'),
    79 sx: {
    80 outline: hoveredTable === 'table-1' ? '2px dashed pink' : undefined,
    81 },
    82 }}
    83 renderTopToolbarCustomActions={() => (
    84 <Typography color="success.main" component="span" variant="h4">
    85 Nice List
    86 </Typography>
    87 )}
    88 />
    89 <MaterialReactTable
    90 {...commonTableProps}
    91 data={data2}
    92 defaultColumn={{
    93 size: 100,
    94 }}
    95 getRowId={(originalRow) => `table-2-${originalRow.firstName}`}
    96 muiTableBodyRowDragHandleProps={{
    97 onDragEnd: () => {
    98 if (hoveredTable === 'table-1') {
    99 setData1((data1) => [...data1, draggingRow!.original]);
    100 setData2((data2) =>
    101 data2.filter((d) => d !== draggingRow!.original),
    102 );
    103 }
    104 setHoveredTable(null);
    105 },
    106 }}
    107 muiTablePaperProps={{
    108 onDragEnter: () => setHoveredTable('table-2'),
    109 sx: {
    110 outline: hoveredTable === 'table-2' ? '2px dashed pink' : undefined,
    111 },
    112 }}
    113 renderTopToolbarCustomActions={() => (
    114 <Typography color="error.main" component="span" variant="h4">
    115 Naughty List
    116 </Typography>
    117 )}
    118 />
    119 </Box>
    120 );
    121};
    122
    123export default Example;
    124

    View Extra Storybook Examples