Examples › Column dragging and toggling

Starting with v7.3, Mantine DataTable supports column toggling and drag-and-drop reordering, thanks to the outstanding work of Giovambattista Fazioli.

Column drag-and-drop reordering

Name
Street address
City
State
Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Goyette Inc8873 Mertz RapidDorthysideID
Runte Inc2996 Ronny MountMcAllenMA
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
No records

In order to enable column dragging you’ll have to:

  • add a storeColumnsKey: 'your_key' property to the DataTable (since the order of the columns is persisted in the local storage);
  • add a draggable: true property to each dragging candidate column;
  • use the useDataTableColumns() hook to get the sorted columns.
'use client';

import { Button, Group, Stack } from '@mantine/core';
import { DataTable, useDataTableColumns } from 'mantine-datatable';
import { companies, type Company } from '~/data';

export default function DraggingExample() {
  const key = 'draggable-example';

  const { effectiveColumns, resetColumnsOrder } = useDataTableColumns<Company>({
    key,
    columns: [
      { accessor: 'name', width: '40%', draggable: true },
      { accessor: 'streetAddress', width: '60%', draggable: true },
      { accessor: 'city', width: 160, draggable: true },
      { accessor: 'state', textAlign: 'right' },
    ],
  });

  return (
    <Stack>
      <DataTable
        withTableBorder
        withColumnBorders
        storeColumnsKey={key}
        records={companies}
        columns={effectiveColumns}
      />
      <Group justify="right">
        <Button onClick={resetColumnsOrder}>Reset Column Order</Button>
      </Group>
    </Stack>
  );
}

Column toggling

In the example below:

  • you can toggle the first 3 columns;
  • the last column is not toggleable and will always be visible;
  • the first column is toggled off by default.

Right-click on the header to select the columns you want to toggle.

21716 Ratke DriveStromanportWY
6389 Dicki StreamSouth GateNH
8873 Mertz RapidDorthysideID
2996 Ronny MountMcAllenMA
632 Broadway AvenueNorth LouieWY
576 Joyce WaysTyraburghKS
7508 Lansdowne RoadShieldsboroughMI
57918 Gwendolyn CirclesSheridanportMI
7057 Stanley RoadKearaburghCA
378 Berta CrescentWest GerryKS
No records

In order to enable column toggling you’ll have to:

  • add a storeColumnsKey: 'your_key' property to the DataTable (since the order of the columns is persisted in the local storage);
  • add a toggleable: true property to each toggling candidate column;
  • use the useDataTableColumns() hook to get the sorted columns.
'use client';

import { Button, Group, Stack, Text } from '@mantine/core';
import { IconBuildingCommunity, IconBuildingSkyscraper, IconMap, IconRoadSign } from '@tabler/icons-react';
import { DataTable, useDataTableColumns } from 'mantine-datatable';
import { companies } from '~/data';

export default function TogglingExample() {
  const key = 'toggleable-example';

  const { effectiveColumns, resetColumnsToggle } = useDataTableColumns({
    key,
    columns: [
      {
        accessor: 'name',
        title: (
          <Group gap={4} mt={-1}>
            <IconBuildingSkyscraper size={16} />
            <Text inherit mt={1}>
              Company
            </Text>
          </Group>
        ),
        width: '40%',
        toggleable: true,
        defaultToggle: false,
      },
      {
        accessor: 'streetAddress',
        title: (
          <Group gap={4} mt={-1}>
            <IconRoadSign size={16} />
            <Text inherit mt={1}>
              Street Address
            </Text>
          </Group>
        ),
        width: '60%',
        toggleable: true,
      },
      {
        accessor: 'city',
        title: (
          <Group gap={4} mt={-1}>
            <IconBuildingCommunity size={16} />
            <Text inherit mt={1}>
              City
            </Text>
          </Group>
        ),
        width: 160,
        toggleable: true,
      },
      {
        accessor: 'state',
        textAlign: 'right',
        title: (
          <Group justify="right">
            <IconMap size={16} />
          </Group>
        ),
      },
    ],
  });

  return (
    <Stack>
      <DataTable
        withTableBorder
        withColumnBorders
        storeColumnsKey={key}
        records={companies}
        columns={effectiveColumns}
      />
      <Group justify="right">
        <Button onClick={resetColumnsToggle}>Reset toggled columns</Button>
      </Group>
    </Stack>
  );
}

Dragging and toggling with context menu reset

Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Goyette Inc8873 Mertz RapidDorthysideID
Runte Inc2996 Ronny MountMcAllenMA
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
No records
'use client';

import { IconColumnRemove, IconColumns3 } from '@tabler/icons-react';
import { DataTable, useDataTableColumns } from 'mantine-datatable';
import { useContextMenu } from 'mantine-contextmenu';
import { companies } from '~/data';

export default function DraggingTogglingResetExample() {
  const { showContextMenu } = useContextMenu();

  const key = 'toggleable-reset-example';

  const { effectiveColumns, resetColumnsOrder, resetColumnsToggle } = useDataTableColumns({
    key,
    columns: [
      { accessor: 'name', width: '40%', toggleable: true, draggable: true },
      { accessor: 'streetAddress', width: '60%', toggleable: true, draggable: true },
      { accessor: 'city', width: 160, toggleable: true, draggable: true },
      { accessor: 'state', textAlign: 'right' },
    ],
  });

  return (
    <DataTable
      withTableBorder
      withColumnBorders
      storeColumnsKey={key}
      records={companies}
      columns={effectiveColumns}
      onRowContextMenu={({ event }) =>
        showContextMenu([
          {
            key: 'reset-toggled-columns',
            icon: <IconColumnRemove size={16} />,
            onClick: resetColumnsToggle,
          },
          {
            key: 'reset-columns-order',
            icon: <IconColumns3 size={16} />,
            onClick: resetColumnsOrder,
          },
        ])(event)
      }
    />
  );
}

Complex usage

Connelly, Feest and Hodkiewicz7057 Stanley RoadKearaburghCA
Cummerata - Kuhlman6389 Dicki StreamSouth GateNH
Doyle, Hodkiewicz and O'Connell576 Joyce WaysTyraburghKS
Feest, Bogan and Herzog21716 Ratke DriveStromanportWY
Goldner, Rohan and Lehner632 Broadway AvenueNorth LouieWY
Goyette Inc8873 Mertz RapidDorthysideID
Rau - O'Hara7508 Lansdowne RoadShieldsboroughMI
Runte Inc2996 Ronny MountMcAllenMA
Shanahan, Robel and Beier378 Berta CrescentWest GerryKS
Tillman - Jacobi57918 Gwendolyn CirclesSheridanportMI
No records
'use client';

import { IconColumnRemove, IconColumns3 } from '@tabler/icons-react';
import { DataTable, useDataTableColumns, type DataTableSortStatus } from 'mantine-datatable';
import sortBy from 'lodash/sortBy';
import { useContextMenu } from 'mantine-contextmenu';
import { useEffect, useState } from 'react';
import { companies, type Company } from '~/data';

export default function DraggingTogglingComplexExample() {
  const { showContextMenu } = useContextMenu();

  const [sortStatus, setSortStatus] = useState<DataTableSortStatus<Company>>({
    columnAccessor: 'name',
    direction: 'asc',
  });

  const [records, setRecords] = useState(sortBy(companies, 'name'));

  useEffect(() => {
    const data = sortBy(companies, sortStatus.columnAccessor) as Company[];
    setRecords(sortStatus.direction === 'desc' ? data.reverse() : data);
  }, [sortStatus]);

  const key = 'toggleable-reset-example';

  const { effectiveColumns, resetColumnsOrder, resetColumnsToggle } = useDataTableColumns({
    key,
    columns: [
      { accessor: 'name', width: '40%', toggleable: true, draggable: true, sortable: true },
      { accessor: 'streetAddress', width: '60%', toggleable: true, draggable: true },
      { accessor: 'city', width: 160, toggleable: true, draggable: true },
      { accessor: 'state', textAlign: 'right' },
    ],
  });

  return (
    <DataTable
      withTableBorder
      withColumnBorders
      storeColumnsKey={key}
      records={records}
      columns={effectiveColumns}
      sortStatus={sortStatus}
      onSortStatusChange={setSortStatus}
      onRowContextMenu={({ event }) =>
        showContextMenu([
          {
            key: 'reset-toggled-columns',
            icon: <IconColumnRemove size={16} />,
            onClick: resetColumnsToggle,
          },
          {
            key: 'reset-columns-order',
            icon: <IconColumns3 size={16} />,
            onClick: resetColumnsOrder,
          },
        ])(event)
      }
    />
  );
}