MRT logoMaterial React Table

On This Page

    Row Ordering (DnD) Feature Guide

    Material React Table has exposed 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
    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, then setting up an onDragEnd event handler on the muiRowDragHandleProps prop.

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

    Demo

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

    1-5 of 5

    Source Code

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

    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 also use them to drag rows to other UI elements in your application or even to other tables. This can be done by setting the enableRowDragging prop to true and setting up an onDragEnd event handler on the muiRowDragHandleProps prop to perform whatever logic you want to happen when a row is dropped.

    Demo

    Nice List
    DylanMurrayEast Daphne
    RaquelKohlerColumbus
    ErvinReingerSouth Linda

    1-3 of 3

    Naughty List
    BrittanyMcCulloughLincoln
    BransonFramiCharleston

    1-2 of 2

    Source Code

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

    View Extra Storybook Examples