Capítulo 33 de 54

Chapter 33: Column Resizing (React) Guide

Core Idea

columnResizingFeature (built on columnSizingFeature — register both, sizing first) adds drag-to-resize via header.getResizeHandler(), with a critical performance decision baked in: columnResizeMode: 'onEnd' (default) only commits the new size when the drag finishes, while 'onChange' re-renders live but can stutter on complex tables unless you take resize state off React's render path entirely.

Key Concepts

  • Setup order matters: tableFeatures({ columnSizingFeature, columnResizingFeature }) — resizing depends on sizing.
  • Enabling: column.getCanResize() defaults true for every column; disable globally with enableColumnResizing: false on the table, or per-column with enableResizing: false on that column def.
  • columnResizeMode: 'onEnd' (default) — column.getSize() doesn't reflect the drag until pointer-up; typically paired with a resize-indicator UI shown mid-drag. 'onChange' — size updates (and thus re-renders) on every drag frame; simpler UX but can degrade FPS on complex/large tables without extra work.
  • columnResizeDirection: 'rtl' flips resize direction for right-to-left layouts (default assumes LTR markup).
  • Wiring the drag handle: header.getResizeHandler() bound to both onMouseDown (desktop) and onTouchStart (mobile) on your resize-handle element — one handler covers both input types.
  • Live resize indicator: column.getIsResizing() plus the transient columnResizing state (deltaOffset, deltaPercentage, isResizingColumn, startOffset, startSize, columnSizingStart) — e.g. translate an indicator by table.state.columnResizing.deltaOffset while column.getIsResizing() is true. This transient state is rarely something you own yourself; if you do, it follows the same external-atom-vs-state/onColumnResizingChange pattern as any other slice.
  • APIs: header.getResizeHandler(), column.getCanResize(), column.getIsResizing(), table.setColumnResizing(updater), table.resetHeaderSizeInfo() / resetHeaderSizeInfo(true).

Worked Example

Performant resizing at scale — the standard 'onChange' + inline-width approach re-renders the whole table every drag frame, which stutters on large/complex tables. The fix is to take column width entirely out of React's render path during a drag:

  1. Subscribe the table-owning component to no resize state — pass a selector returning a constant (e.g. () => ({})) so resize state changes never trigger its re-render.
  2. Write widths as CSS custom properties imperatively, not through React state: in a useLayoutEffect, subscribe to table.atoms.columnSizing and set --header-<id>-size/--col-<id>-size directly on the <table> DOM node; cells reference them via width: calc(var(--col-firstName-size) * 1px). The browser repaints on the CSS variable change with zero React re-render per frame. (The core resize handler already coalesces pointer events to one update per animation frame, so this isn't fighting the browser's own throttling.)
  3. Isolate only what must visually react into small table.Subscribe islands — e.g. the active resizer's highlight — so a drag re-renders those tiny islands only, never the table body.

This supersedes the older "memoize the table body during resize" trick: once the body doesn't subscribe to resize state at all, it needs no special memoization — it only re-renders when actual data changes.

Key Takeaways

  1. Default to 'onEnd' unless you specifically need live-updating widths; it's the safer performance default for anything beyond a small/simple table.
  2. If you need 'onChange'-quality live feedback on a large table, go straight to the CSS-variable + useLayoutEffect + Subscribe-islands pattern rather than fighting React re-renders.
  3. header.getResizeHandler() already handles both mouse and touch — bind it to both events, don't hand-roll separate touch logic.

Connects To

  • Column Sizing (React) Guide: the state layer this feature builds on.
  • Table State (React) Guide: the atoms/Subscribe model the performant pattern relies on.
  • Virtualization (React) Guide: another large-table performance pattern that similarly avoids per-frame React re-renders.