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.