Capítulo 30 de 54

Chapter 30: Column Ordering (React) Guide

Core Idea

Column order is decided by a fixed three-stage pipeline (pinning → manual columnOrder → grouping), and manual reordering is just table.setColumnOrder(newIdArray) wired to whatever drag-and-drop library you choose — the library only owns the drag interaction, never the ordering state itself.

Key Concepts

  • Order pipeline, always in this sequence: (1) column pinning splits columns into start/center/end regions; (2) the manual columnOrder state reorders within those regions (it only affects unpinned/center columns unless pinning isn't used); (3) if grouping is active and groupedColumnMode is 'reorder' or 'remove', grouped columns move to the front of the flow.
  • Without a columnOrder state, columns render in columns array definition order.
  • Set starting order via initialState.columnOrder: ['id1', 'id2', ...]; don't also pass state.columnOrder at the same time — state wins and makes initialState a no-op for that slice (pick one).
  • Ownership: external atom via atoms: { columnOrder: atom } (v9-recommended, fine-grained subscriptions elsewhere in the app) or classic state.columnOrder + onColumnOrderChange (simpler, less granular). table.setColumnOrder works identically regardless of which ownership mode is in play.
  • Wiring drag-and-drop: on drop, compute the new id array and call table.setColumnOrder(...). The official example pairs DnD Kit's arrayMove with the drag-end event's active.id/over.id. TanStack Table has no opinion on which DnD library you use — DnD Kit (modular, Strict Mode-safe, plays well with semantic <table>) is the one the official examples use; native onDragStart/onDragEnter/onDragEnd events are a zero-dependency alternative if you're willing to handle touch support yourself; older libraries (react-dnd, react-beautiful-dnd) are no longer actively maintained — Atlassian's Pragmatic drag and drop is the maintained successor in that API family.
  • APIs: table.setColumnOrder([...]), table.resetColumnOrder() (→ initialState.columnOrder), table.resetColumnOrder(true) (→ empty/default order). Position-reading helpers: column.getIndex() / getIndex('start' | 'center' | 'end'), column.getIsFirstColumn(), column.getIsLastColumn() — useful for boundary styling or drag-target logic that needs the current rendered order (post pinning/ordering/grouping).

Code Examples

const features = tableFeatures({ columnOrderingFeature })
const table = useTable({ features, columns, data, initialState: { columnOrder: ['lastName', 'firstName', 'age'] } })

function handleDragEnd({ active, over }: DragEndEvent) {
  if (!over || active.id === over.id) return
  table.setColumnOrder((prev) => arrayMove(prev, prev.indexOf(active.id as string), prev.indexOf(over.id as string)))
}
  • What it demonstrates: the entire drag-and-drop integration surface is one setColumnOrder call in a drop handler — the table doesn't need to know which DnD library produced the new order.

Key Takeaways

  1. Remember the fixed pipeline order (pin → manual order → group) when a column doesn't end up where expected — check pinning/grouping state before assuming columnOrder is wrong.
  2. Only one of initialState.columnOrder or state.columnOrder should be set — not both.
  3. setColumnOrder is DnD-library-agnostic; the library only needs to produce a reordered id array.

Connects To

  • Column Pinning (React) Guide: the region split that happens before manual ordering.
  • Grouping (React) Guide: groupedColumnMode, the stage that happens after manual ordering.
  • Table State (React) Guide: external atoms vs. classic state/on[X]Change in full.