Skip to content

Column DnD Table

Drag-and-drop column reordering with composable primitives.

Drag column headers to reorder them, wired through DataTableColumnDndProvider on top of @dnd-kit. Unlike row DnD, column DnD is safe to combine with sorting, filtering, and virtualization — the user’s column order is independent of the row model.

Open in
Employee IDNameDepartmentRoleLocationStatus
EMP-001
Alice Johnson
EngineeringSenior DeveloperNew Yorkactive
EMP-002
Bob Smith
DesignUI DesignerSan Franciscoremote
EMP-003
Carol Williams
MarketingMarketing LeadChicagoactive
EMP-004
David Brown
EngineeringBackend DeveloperAustinon-leave
EMP-005
Eva Martinez
ProductProduct ManagerSeattleactive
EMP-006
Frank Lee
EngineeringDevOps EngineerDenverremote
EMP-007
Grace Kim
DesignUX ResearcherPortlandactive
EMP-008
Henry Davis
SalesAccount ExecutiveBostonactive
Preview with Controlled State
Open in
Employee IDNameDepartmentRoleLocationStatus
EMP-001
Alice Johnson
EngineeringSenior DeveloperNew Yorkactive
EMP-002
Bob Smith
DesignUI DesignerSan Franciscoremote
EMP-003
Carol Williams
MarketingMarketing LeadChicagoactive
EMP-004
David Brown
EngineeringBackend DeveloperAustinon-leave
EMP-005
Eva Martinez
ProductProduct ManagerSeattleactive
EMP-006
Frank Lee
EngineeringDevOps EngineerDenverremote
EMP-007
Grace Kim
DesignUX ResearcherPortlandactive
EMP-008
Henry Davis
SalesAccount ExecutiveBostonactive
Column DnD State
Header drag, view-menu drag, visibility toggles, and search — all live state.
Total Columns:6
Current Order:id → name → department → role → location → status
Hidden:none
Search:
View Full State
{
  "columnOrder": [
    "id",
    "name",
    "department",
    "role",
    "location",
    "status"
  ],
  "columnVisibility": {},
  "globalFilter": ""
}

For large datasets, use DataTableVirtualizedDndHeader and DataTableVirtualizedDndColumnBody which combine row virtualization with column drag-and-drop. Same <DataTableColumnResize /> marker — drag a header to reorder, drag the edge grip to resize (grip stops propagation so it won’t start a reorder).

Open in
Employee IDNameEmailDepartmentRoleLocationStatusSalary

Column DnD lets users reorder table columns by dragging headers. Built with @dnd-kit and composable primitives following the shadcn/ui open-code pattern.

Install the DataTable core and column DnD add-ons. Add data-table-view-dnd-menu and data-table-search-filter for the toolbar shown in the example:

pnpm dlx shadcn@latest add @niko-table/data-table @niko-table/data-table-column-dnd @niko-table/data-table-column-resize @niko-table/data-table-view-dnd-menu @niko-table/data-table-search-filter @niko-table/data-table-virtualized @niko-table/data-table-virtualized-column-dnd

First time using @niko-table? See the Installation Guide to set up the registry.

For other add-ons or manual copy-paste, see the Installation Guide.

Three components work together:

  1. DataTableColumnDndProvider — Wraps the table with horizontal DnD context
  2. DataTableDndHeader — Renders headers as draggable items
  3. DataTableDndColumnBody — Cells follow column drag position
column-dnd.tsx
import {
DataTableDndHeader,
DataTableDndColumnBody,
} from "@/components/niko-table/core/data-table-column-dnd-structure"
const [columnOrder, setColumnOrder] = React.useState<string[]>(() =>
columns.map(c => c.id as string),
)
return (
<DataTableRoot
data={data}
columns={columns}
state={{ columnOrder }}
onColumnOrderChange={setColumnOrder}
>
<DataTableColumnResize />
<DataTableColumnDndProvider
columnOrder={columnOrder}
onColumnOrderChange={setColumnOrder}
>
<DataTable>
<DataTableDndHeader />
<DataTableDndColumnBody />
</DataTable>
</DataTableColumnDndProvider>
</DataTableRoot>
)

DataTableViewDndMenu is a drag-to-reorder variant of the View menu that shares the same columnOrder state as the column-header drag. Users get two ways to reorder, and visibility toggles + a Reset live in the same dropdown:

column-dnd.tsx
<DataTableToolbarSection className="justify-between">
<DataTableSearchFilter placeholder="Search employees..." />
<DataTableViewDndMenu
columnOrder={columnOrder}
onColumnOrderChange={setColumnOrder}
onReset={() => setColumnOrder(initialColumnOrder)}
/>
</DataTableToolbarSection>

Use DataTableViewMenu (no DnD) instead if you don’t need drag-to-reorder — it skips the @dnd-kit/* bundle.

  • Every column needs an explicit id field for column order tracking
  • columnOrder state must be passed to both DataTableRoot and DataTableColumnDndProvider — and DataTableViewDndMenu if you use it
  • Headers are draggable by default — grab any header to reorder
  • Safe to combine with sorting and filtering — column order is independent of data order, unlike Row DnD
  • DataTableViewDndMenu and the column-header drag share state, so both surfaces stay in lockstep

✅ Use Column DnD when:

  • Users want to customize their table layout
  • Different users prefer different column arrangements
  • Building configurable dashboards

❌ Consider other options when:

  • Column order is fixed by design
  • Tables have very few columns