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

#
Prop Name
Type
Default Value
More Info Links
1boolean
2boolean
3ActionIconProps | ({ row, table }) => ActionIconPropsMantine ActionIcon Docs
4OnChangeFn<MRT_Row<TData> | null>
5OnChangeFn<MRT_Row<TData> | null>

Relevant State

#
State Option
Type
Default Value
More Info Links
1MRT_Row | null
2MRT_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
    },
  },
});
Move
First Name
Last Name
City
DylanMurrayEast Daphne
RaquelKohlerColumbus
ErvinReingerSouth Linda
BrittanyMcCulloughLincoln
BransonFramiCharleston

Rows per page

1-5 of 5

import '@mantine/core/styles.css';
import '@mantine/dates/styles.css'; //if using mantine date picker features
import 'mantine-react-table/styles.css'; //make sure MRT styles were imported in your app root (once)
import { useMemo, useState } from 'react';
import {
  MantineReactTable,
  type MRT_ColumnDef,
  type MRT_Row,
} from 'mantine-react-table';
import { data as initData, type Person } from './makeData';

const Example = () => {
  const columns = useMemo<MRT_ColumnDef<Person>[]>(
    () => [
      {
        accessorKey: 'firstName',
        header: 'First Name',
      },
      {
        accessorKey: 'lastName',
        header: 'Last Name',
      },
      {
        accessorKey: 'city',
        header: 'City',
      },
    ],
    [],
  );

  const [data, setData] = useState(() => initData);

  return (
    <MantineReactTable
      autoResetPageIndex={false}
      columns={columns}
      data={data}
      enableRowOrdering
      enableSorting={false}
      mantineRowDragHandleProps={({ table }) => ({
        onDragEnd: () => {
          const { draggingRow, hoveredRow } = table.getState();
          if (hoveredRow && draggingRow) {
            data.splice(
              (hoveredRow as MRT_Row<Person>).index,
              0,
              data.splice(draggingRow.index, 1)[0],
            );
            setData([...data]);
          }
        },
      })}
    />
  );
};

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

Move
First Name
Last Name
City
DylanMurrayEast Daphne
RaquelKohlerColumbus
ErvinReingerSouth Linda

Rows per page

1-3 of 3

Naughty List

Move
First Name
Last Name
City
BrittanyMcCulloughLincoln
BransonFramiCharleston

Rows per page

1-2 of 2

import '@mantine/core/styles.css';
import '@mantine/dates/styles.css'; //if using mantine date picker features
import 'mantine-react-table/styles.css'; //make sure MRT styles were imported in your app root (once)
import { useMemo, useState } from 'react';
import {
  MantineReactTable,
  MRT_TableOptions,
  MRT_ColumnDef,
  MRT_Row,
} from 'mantine-react-table';
import { Box, Title } from '@mantine/core';
import { data, type Person } from './makeData';
import { useMediaQuery } from '@mantine/hooks';

const Example = () => {
  const columns = useMemo<MRT_ColumnDef<Person>[]>(
    () => [
      {
        accessorKey: 'firstName',
        header: 'First Name',
      },
      {
        accessorKey: 'lastName',
        header: 'Last Name',
      },
      {
        accessorKey: 'city',
        header: 'City',
      },
    ],
    [],
  );

  const [data1, setData1] = useState<Person[]>(() => data.slice(0, 3));
  const [data2, setData2] = useState<Person[]>(() => data.slice(3, 5));

  const [draggingRow, setDraggingRow] = useState<MRT_Row<Person> | null>(null);
  const [hoveredTable, setHoveredTable] = useState<string | null>(null);

  const isMobile = useMediaQuery(`(max-width: 960px)`);

  const commonTableProps: Partial<MRT_TableOptions<Person>> & {
    columns: MRT_ColumnDef<Person>[];
  } = {
    columns,
    enableRowDragging: true,
    enableFullScreenToggle: false,
    mantineTableContainerProps: {
      style: {
        minHeight: '320px',
      },
    },
    onDraggingRowChange: setDraggingRow,
    state: { draggingRow },
  };

  return (
    <Box
      style={{
        display: 'grid',
        gridTemplateColumns: isMobile ? 'auto' : '1fr 1fr',
        gap: '16px',
        overflow: 'auto',
        padding: '4px',
      }}
    >
      <MantineReactTable
        {...commonTableProps}
        data={data1}
        getRowId={(originalRow) => `table-1-${originalRow.firstName}`}
        mantineRowDragHandleProps={{
          onDragEnd: () => {
            if (hoveredTable === 'table-2') {
              setData2((data2) => [...data2, draggingRow!.original]);
              setData1((data1) =>
                data1.filter((d) => d !== draggingRow!.original),
              );
            }
            setHoveredTable(null);
          },
        }}
        mantinePaperProps={{
          onDragEnter: () => setHoveredTable('table-1'),
          style: {
            outline: hoveredTable === 'table-1' ? '2px dashed pink' : undefined,
          },
        }}
        renderTopToolbarCustomActions={() => (
          <Title c="green" order={4}>
            Nice List
          </Title>
        )}
      />
      <MantineReactTable
        {...commonTableProps}
        data={data2}
        defaultColumn={{
          size: 100,
        }}
        getRowId={(originalRow) => `table-2-${originalRow.firstName}`}
        mantineRowDragHandleProps={{
          onDragEnd: () => {
            if (hoveredTable === 'table-1') {
              setData1((data1) => [...data1, draggingRow!.original]);
              setData2((data2) =>
                data2.filter((d) => d !== draggingRow!.original),
              );
            }
            setHoveredTable(null);
          },
        }}
        mantinePaperProps={{
          onDragEnter: () => setHoveredTable('table-2'),
          style: {
            outline: hoveredTable === 'table-2' ? '2px dashed pink' : undefined,
          },
        }}
        renderTopToolbarCustomActions={() => (
          <Title c="red" order={4}>
            Naughty List
          </Title>
        )}
      />
    </Box>
  );
};

export default Example;

View Extra Storybook Examples

Note: Drag and Drop is not currently supported on mobile touch devices.