Column reordering

Set reorder: true on any column definition to make that header draggable. Users drag a header cell left or right to swap it with the column it's dropped on. The onColumnOrderChange callback fires after every swap with the updated column array.

Drag to reorder columns

Grab any column header and drag it to a new position. The current order is shown below the table.

Drag any column header to reorder it.

Name
Role
Department
Salary
Aria Chen
Engineering Lead
Engineering
$155,000
Marcus Webb
Product Manager
Product
$132,000
Priya Kapoor
Senior Designer
Design
$118,000
Jordan Ellis
Data Scientist
Analytics
$143,000
Sam Rivera
DevOps Engineer
Engineering
$128,000

Current order: name → role → department → salary

Enabling reorder per column

reorder is a per-column flag, not a table-level prop. Columns without it are fixed in place. This lets you pin identity columns (e.g. a row number or name) while keeping the rest draggable.

const columns: TableColumn<Employee>[] = [
  { id: 'name',   name: 'Name',   selector: r => r.name,   /* no reorder — pinned */ },
  { id: 'role',   name: 'Role',   selector: r => r.role,   reorder: true },
  { id: 'dept',   name: 'Dept',   selector: r => r.dept,   reorder: true },
  { id: 'salary', name: 'Salary', selector: r => r.salary, reorder: true },
];

Persisting column order

Column order is in-memory only and resets on remount. Persist it via localStorage by saving the ordered column IDs and restoring them on init:

const STORAGE_KEY = 'my-table-col-order';

function applyOrder(cols: TableColumn<Employee>[], order: string[]) {
  if (!order.length) return cols;
  return [...cols].sort((a, b) => order.indexOf(String(a.id)) - order.indexOf(String(b.id)));
}

function loadOrder(): string[] {
  try { return JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]'); }
  catch { return []; }
}

export default function App() {
  const [columns, setColumns] = useState(() => applyOrder(initialColumns, loadOrder()));

  function handleOrderChange(next: TableColumn<Employee>[]) {
    setColumns(next);
    localStorage.setItem(STORAGE_KEY, JSON.stringify(next.map(c => String(c.id))));
  }

  return (
    <DataTable columns={columns} data={data} onColumnOrderChange={handleOrderChange} />
  );
}

Reordering column groups

When using columnGroups, set reorder: true on each group instead of on individual columns. Dragging a group header moves all of its member columns as a single block, keeping spans intact. Use onColumnGroupOrderChange to receive both the new group order and the matching column array.

Drag to reorder groups

Grab a group header (Employee or Compensation) and drag it to swap the two groups.

Drag a group header to move the whole group. Drag an individual column header to reorder it within its group.

Aria
Chen
Engineering
$140,000
$15,000
Marcus
Webb
Product
$125,000
$7,000
Priya
Kapoor
Design
$110,000
$8,000
Jordan
Ellis
Analytics
$135,000
$12,000
Sam
Rivera
Engineering
$120,000
$9,000

Group order: Employee → Compensation

You can combine both — set reorder: true on columns AND on groups. Column drag is automatically restricted to within the same group, so spans stay correct. Group drag moves the entire block. This mirrors the AG Grid reorder experience.

const columns: TableColumn<Employee>[] = [
  { id: 'first', name: 'First name',  selector: r => r.firstName,  sortable: true, reorder: true },
  { id: 'last',  name: 'Last name',   selector: r => r.lastName,   sortable: true, reorder: true },
  { id: 'dept',  name: 'Department',  selector: r => r.department, sortable: true, reorder: true },
  { id: 'base',  name: 'Base salary', selector: r => r.baseSalary, sortable: true, reorder: true },
  { id: 'bonus', name: 'Bonus',       selector: r => r.bonus,      sortable: true, reorder: true },
];

const columnGroups: ColumnGroup[] = [
  { name: 'Employee',     columnIds: ['first', 'last', 'dept'], reorder: true },
  { name: 'Compensation', columnIds: ['base', 'bonus'],         reorder: true },
];