@tanstack/table-core 9.0.0-beta.37 → 9.0.0-beta.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +1 -0
  2. package/dist/core/headers/buildHeaderGroups.cjs.map +1 -1
  3. package/dist/core/headers/buildHeaderGroups.d.cts +1 -1
  4. package/dist/core/headers/buildHeaderGroups.d.ts +1 -1
  5. package/dist/core/headers/buildHeaderGroups.js.map +1 -1
  6. package/dist/core/headers/coreHeadersFeature.utils.cjs +7 -7
  7. package/dist/core/headers/coreHeadersFeature.utils.cjs.map +1 -1
  8. package/dist/core/headers/coreHeadersFeature.utils.js +7 -7
  9. package/dist/core/headers/coreHeadersFeature.utils.js.map +1 -1
  10. package/dist/core/table/coreTablesFeature.utils.cjs +1 -1
  11. package/dist/core/table/coreTablesFeature.utils.cjs.map +1 -1
  12. package/dist/core/table/coreTablesFeature.utils.js +1 -1
  13. package/dist/core/table/coreTablesFeature.utils.js.map +1 -1
  14. package/dist/features/column-ordering/columnOrderingFeature.types.d.cts +5 -5
  15. package/dist/features/column-ordering/columnOrderingFeature.types.d.ts +5 -5
  16. package/dist/features/column-ordering/columnOrderingFeature.utils.cjs +6 -6
  17. package/dist/features/column-ordering/columnOrderingFeature.utils.cjs.map +1 -1
  18. package/dist/features/column-ordering/columnOrderingFeature.utils.d.cts +3 -3
  19. package/dist/features/column-ordering/columnOrderingFeature.utils.d.ts +3 -3
  20. package/dist/features/column-ordering/columnOrderingFeature.utils.js +6 -6
  21. package/dist/features/column-ordering/columnOrderingFeature.utils.js.map +1 -1
  22. package/dist/features/column-pinning/columnPinningFeature.cjs +44 -39
  23. package/dist/features/column-pinning/columnPinningFeature.cjs.map +1 -1
  24. package/dist/features/column-pinning/columnPinningFeature.d.cts +6 -1
  25. package/dist/features/column-pinning/columnPinningFeature.d.ts +6 -1
  26. package/dist/features/column-pinning/columnPinningFeature.js +45 -40
  27. package/dist/features/column-pinning/columnPinningFeature.js.map +1 -1
  28. package/dist/features/column-pinning/columnPinningFeature.types.d.cts +49 -38
  29. package/dist/features/column-pinning/columnPinningFeature.types.d.ts +49 -38
  30. package/dist/features/column-pinning/columnPinningFeature.utils.cjs +154 -146
  31. package/dist/features/column-pinning/columnPinningFeature.utils.cjs.map +1 -1
  32. package/dist/features/column-pinning/columnPinningFeature.utils.d.cts +81 -73
  33. package/dist/features/column-pinning/columnPinningFeature.utils.d.ts +81 -73
  34. package/dist/features/column-pinning/columnPinningFeature.utils.js +141 -133
  35. package/dist/features/column-pinning/columnPinningFeature.utils.js.map +1 -1
  36. package/dist/features/column-sizing/columnSizingFeature.cjs +4 -4
  37. package/dist/features/column-sizing/columnSizingFeature.cjs.map +1 -1
  38. package/dist/features/column-sizing/columnSizingFeature.js +5 -5
  39. package/dist/features/column-sizing/columnSizingFeature.js.map +1 -1
  40. package/dist/features/column-sizing/columnSizingFeature.types.d.cts +18 -12
  41. package/dist/features/column-sizing/columnSizingFeature.types.d.ts +18 -12
  42. package/dist/features/column-sizing/columnSizingFeature.utils.cjs +24 -20
  43. package/dist/features/column-sizing/columnSizingFeature.utils.cjs.map +1 -1
  44. package/dist/features/column-sizing/columnSizingFeature.utils.d.cts +18 -14
  45. package/dist/features/column-sizing/columnSizingFeature.utils.d.ts +18 -14
  46. package/dist/features/column-sizing/columnSizingFeature.utils.js +24 -20
  47. package/dist/features/column-sizing/columnSizingFeature.utils.js.map +1 -1
  48. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs +16 -16
  49. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs.map +1 -1
  50. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.cts +3 -3
  51. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.ts +3 -3
  52. package/dist/features/column-visibility/columnVisibilityFeature.utils.js +16 -16
  53. package/dist/features/column-visibility/columnVisibilityFeature.utils.js.map +1 -1
  54. package/dist/static-functions.cjs +16 -16
  55. package/dist/static-functions.d.cts +3 -3
  56. package/dist/static-functions.d.ts +3 -3
  57. package/dist/static-functions.js +3 -3
  58. package/package.json +1 -1
  59. package/skills/api-not-found/SKILL.md +113 -0
  60. package/skills/client-vs-server/SKILL.md +164 -0
  61. package/skills/column-faceting/SKILL.md +91 -0
  62. package/skills/column-filtering/SKILL.md +82 -0
  63. package/skills/column-ordering/SKILL.md +75 -0
  64. package/skills/column-pinning/SKILL.md +89 -0
  65. package/skills/column-resizing/SKILL.md +91 -0
  66. package/skills/column-sizing/SKILL.md +72 -0
  67. package/skills/column-visibility/SKILL.md +75 -0
  68. package/skills/core/SKILL.md +140 -0
  69. package/skills/custom-features/SKILL.md +207 -0
  70. package/skills/expanding/SKILL.md +80 -0
  71. package/skills/global-filtering/SKILL.md +84 -0
  72. package/skills/grouping/SKILL.md +50 -394
  73. package/skills/migrate-v8-to-v9/SKILL.md +230 -390
  74. package/skills/pagination/SKILL.md +35 -344
  75. package/skills/row-pinning/SKILL.md +47 -238
  76. package/skills/row-selection/SKILL.md +39 -351
  77. package/skills/sorting/SKILL.md +35 -299
  78. package/skills/table-features/SKILL.md +153 -0
  79. package/skills/typescript/SKILL.md +126 -0
  80. package/src/core/headers/buildHeaderGroups.ts +1 -1
  81. package/src/core/headers/coreHeadersFeature.utils.ts +7 -7
  82. package/src/core/table/coreTablesFeature.utils.ts +1 -1
  83. package/src/features/column-ordering/columnOrderingFeature.types.ts +5 -5
  84. package/src/features/column-ordering/columnOrderingFeature.utils.ts +9 -9
  85. package/src/features/column-pinning/columnPinningFeature.ts +64 -59
  86. package/src/features/column-pinning/columnPinningFeature.types.ts +49 -38
  87. package/src/features/column-pinning/columnPinningFeature.utils.ts +163 -155
  88. package/src/features/column-sizing/columnSizingFeature.ts +6 -6
  89. package/src/features/column-sizing/columnSizingFeature.types.ts +18 -12
  90. package/src/features/column-sizing/columnSizingFeature.utils.ts +31 -27
  91. package/src/features/column-visibility/columnVisibilityFeature.utils.ts +15 -15
  92. package/skills/column-definitions/SKILL.md +0 -330
  93. package/skills/column-layout/SKILL.md +0 -326
  94. package/skills/column-layout/references/subsystems.md +0 -220
  95. package/skills/customizing-feature-behavior/SKILL.md +0 -423
  96. package/skills/filtering/SKILL.md +0 -375
  97. package/skills/filtering/references/faceting-and-fuzzy.md +0 -218
  98. package/skills/row-expanding/SKILL.md +0 -356
  99. package/skills/setup/SKILL.md +0 -390
  100. package/skills/state-management/SKILL.md +0 -403
@@ -1,326 +0,0 @@
1
- ---
2
- name: column-layout
3
- description: >
4
- The five UI-state-only column features in TanStack Table v9 that shape how
5
- columns render — visibility, ordering, pinning, sizing, resizing. None
6
- require a row model. Covers `columnVisibilityFeature` (getVisibleLeafColumns,
7
- row.getVisibleCells), `columnOrderingFeature` (columnOrder string[], column.getIndex),
8
- `columnPinningFeature` (left/right ColumnPinningState, column.pin, column.getStart /
9
- getAfter, split-table getLeft*/getCenter*/getRight* APIs, sticky-CSS pattern;
10
- `enableColumnPinning` table-level option distinct from per-column `enablePinning`),
11
- `columnSizingFeature` (defaultColumnSizing, column.getSize, table.getTotalSize),
12
- `columnResizingFeature` (columnResizeMode 'onEnd'/'onChange', columnResizeDirection
13
- 'ltr'/'rtl', header.getResizeHandler for mouse + touch, CSS-variable
14
- performant resize pattern). Pipeline: Column Pinning → columnOrder → Grouping.
15
- type: core
16
- library: tanstack-table
17
- library_version: '9.0.0-alpha.48'
18
- requires:
19
- - state-management
20
- sources:
21
- - TanStack/table:docs/guide/column-visibility.md
22
- - TanStack/table:docs/guide/column-ordering.md
23
- - TanStack/table:docs/guide/column-pinning.md
24
- - TanStack/table:docs/guide/column-sizing.md
25
- - TanStack/table:docs/guide/column-resizing.md
26
- - TanStack/table:examples/react/column-visibility/src/main.tsx
27
- - TanStack/table:examples/react/column-resizing/src/main.tsx
28
- - TanStack/table:examples/react/column-resizing-performant/src/main.tsx
29
- - TanStack/table:examples/react/column-pinning-split/src/main.tsx
30
- - TanStack/table:examples/react/column-pinning-sticky/src/main.tsx
31
- - TanStack/table:examples/react/column-dnd/src/main.tsx
32
- ---
33
-
34
- This skill builds on `tanstack-table/state-management`. Read it first for the atom model — these are UI-state-only features (no row model).
35
-
36
- ## Setup
37
-
38
- All five features are opt-in via `tableFeatures({...})`. The reorder pipeline is fixed: **(1) Column Pinning splits into left/center/right → (2) `columnOrder` reorders the center → (3) Grouping (`groupedColumnMode: 'reorder' | 'remove'`) may move grouped columns to the front.**
39
-
40
- ```ts
41
- import {
42
- tableFeatures,
43
- columnVisibilityFeature,
44
- columnOrderingFeature,
45
- columnPinningFeature,
46
- columnSizingFeature,
47
- columnResizingFeature,
48
- constructTable,
49
- } from '@tanstack/table-core'
50
-
51
- const features = tableFeatures({
52
- columnVisibilityFeature,
53
- columnOrderingFeature,
54
- columnPinningFeature,
55
- columnSizingFeature,
56
- columnResizingFeature, // explicit — formerly part of v8 ColumnSizing
57
- })
58
-
59
- const table = constructTable({
60
- features,
61
- columns,
62
- data,
63
- initialState: {
64
- columnVisibility: {},
65
- columnOrder: [],
66
- columnPinning: { left: [], right: [] },
67
- columnSizing: {},
68
- },
69
- })
70
- ```
71
-
72
- ## Subsystems
73
-
74
- | Feature | State slice | Key APIs |
75
- | ------------------------- | ---------------------- | ---------------------------------------------------- |
76
- | `columnVisibilityFeature` | `columnVisibility` | `column.toggleVisibility()`, `row.getVisibleCells()` |
77
- | `columnOrderingFeature` | `columnOrder` | `table.setColumnOrder()`, `column.getIndex()` |
78
- | `columnPinningFeature` | `columnPinning` (l/r) | `column.pin()`, `column.getStart()`, `getAfter()` |
79
- | `columnSizingFeature` | `columnSizing` | `column.getSize()`, `table.getTotalSize()` |
80
- | `columnResizingFeature` | (transient drag state) | `header.getResizeHandler()`, `columnResizeMode` |
81
-
82
- Full API surface, render strategies, and additional MEDIUM-priority failure modes (reorder-pinned-via-columnOrder, react-dnd/react-beautiful-dnd avoidance, touch-resize handler) in [subsystems.md](references/subsystems.md).
83
-
84
- ## Core Patterns
85
-
86
- ### Performant `'onChange'` resize (React)
87
-
88
- ```tsx
89
- // From examples/react/column-resizing-performant/src/main.tsx
90
- const columnSizeVars = React.useMemo(() => {
91
- const headers = table.getFlatHeaders()
92
- const colSizes: { [key: string]: number } = {}
93
- for (const header of headers) {
94
- colSizes[`--header-${header.id}-size`] = header.getSize()
95
- colSizes[`--col-${header.column.id}-size`] = header.column.getSize()
96
- }
97
- return colSizes
98
- }, [table.state.columnResizing, table.state.columnSizing])
99
-
100
- <div className="divTable" style={{ ...columnSizeVars, width: table.getTotalSize() }}>
101
- {table.store.state.columnResizing.isResizingColumn
102
- ? <MemoizedTableBody table={table} />
103
- : <TableBody table={table} />}
104
- </div>
105
-
106
- // Body cells use the CSS variable (no per-cell getSize() call)
107
- <div className="td" style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}>
108
- {cell.renderValue()}
109
- </div>
110
-
111
- export const MemoizedTableBody = React.memo(
112
- TableBody,
113
- (prev, next) => prev.table.options.data === next.table.options.data,
114
- )
115
- ```
116
-
117
- ## Common Mistakes
118
-
119
- ### [HIGH] Rendering body cells with `row.getAllCells()` while visibility is registered
120
-
121
- Wrong:
122
-
123
- ```tsx
124
- // Toggling visibility has no effect on rendered cells
125
- {
126
- table.getAllLeafColumns().map((column) => <th key={column.id}>...</th>)
127
- }
128
- {
129
- row.getAllCells().map((cell) => (
130
- <td key={cell.id}>
131
- <table.FlexRender cell={cell} />
132
- </td>
133
- ))
134
- }
135
- ```
136
-
137
- Correct:
138
-
139
- ```tsx
140
- // Header groups already respect visibility; use them for headers.
141
- // For body cells, swap getAllCells → getVisibleCells.
142
- <thead>
143
- {table.getHeaderGroups().map((headerGroup) => (
144
- <tr key={headerGroup.id}>
145
- {headerGroup.headers.map((header) => (
146
- <th key={header.id} colSpan={header.colSpan}>
147
- {header.isPlaceholder ? null : <table.FlexRender header={header} />}
148
- </th>
149
- ))}
150
- </tr>
151
- ))}
152
- </thead>
153
- <tbody>
154
- {table.getRowModel().rows.map((row) => (
155
- <tr key={row.id}>
156
- {row.getVisibleCells().map((cell) => (
157
- <td key={cell.id}><table.FlexRender cell={cell} /></td>
158
- ))}
159
- </tr>
160
- ))}
161
- </tbody>
162
- ```
163
-
164
- The `getAll*` accessors do NOT consult `columnVisibility` state. Only `Visible` variants and header-group APIs filter by visibility.
165
-
166
- Source: docs/guide/column-visibility.md; examples/react/column-visibility/src/main.tsx
167
-
168
- ### [HIGH] `columnResizeMode: 'onChange'` + `column.getSize()` per cell + un-memoized body
169
-
170
- Wrong:
171
-
172
- ```tsx
173
- const table = useTable({
174
- features: tableFeatures({ columnSizingFeature, columnResizingFeature }),
175
- columnResizeMode: 'onChange',
176
- })
177
- <td style={{ width: cell.column.getSize() }}>{cell.renderValue()}</td>
178
- ```
179
-
180
- Correct:
181
-
182
- ```tsx
183
- // See "Performant 'onChange' resize" above — CSS variables + memoized body
184
- const columnSizeVars = React.useMemo(() => {
185
- /* … */
186
- }, [table.state.columnResizing, table.state.columnSizing])
187
-
188
- {
189
- table.store.state.columnResizing.isResizingColumn ? (
190
- <MemoizedTableBody table={table} />
191
- ) : (
192
- <TableBody table={table} />
193
- )
194
- }
195
-
196
- ;<div
197
- className="td"
198
- style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}
199
- />
200
- ```
201
-
202
- `'onChange'` commits a new `columnSizing` map on every pointer move. Per-cell `getSize()` blows the 16ms frame budget. The CSS-variable pattern caches widths once per resize batch.
203
-
204
- Source: docs/guide/column-resizing.md; examples/react/column-resizing-performant/src/main.tsx
205
-
206
- ### [HIGH] Using v8 `enablePinning` at the table level
207
-
208
- Wrong:
209
-
210
- ```ts
211
- // v8 syntax — no longer disables pinning at table level in v9
212
- const table = useTable({
213
- features: tableFeatures({ columnPinningFeature }),
214
- enablePinning: false, // ignored
215
- })
216
- ```
217
-
218
- Correct:
219
-
220
- ```ts
221
- // v9 split: two distinct table-level options
222
- const table = useTable({
223
- features: tableFeatures({ columnPinningFeature, rowPinningFeature }),
224
- enableColumnPinning: false,
225
- enableRowPinning: false,
226
- })
227
-
228
- // Per-column opt-out is still spelled `enablePinning`:
229
- columnHelper.accessor('id', {
230
- enablePinning: false, // this column can't be pinned
231
- })
232
- ```
233
-
234
- v9 split `enablePinning` into `enableColumnPinning` and `enableRowPinning`. The bare name now refers ONLY to per-column opt-out.
235
-
236
- Source: packages/table-core/src/features/column-pinning/columnPinningFeature.types.ts
237
-
238
- ### [HIGH] Defining `columns` inline (infinite loop once a layout feature commits state)
239
-
240
- Wrong:
241
-
242
- ```tsx
243
- function App() {
244
- const columns = [
245
- columnHelper.accessor('firstName', {
246
- /* … */
247
- }),
248
- columnHelper.accessor('lastName', {
249
- /* … */
250
- }),
251
- ]
252
- const table = useTable({
253
- features: tableFeatures({ columnPinningFeature, columnResizingFeature }),
254
- columns,
255
- data,
256
- })
257
- }
258
- ```
259
-
260
- Correct:
261
-
262
- ```tsx
263
- const defaultColumns = columnHelper.columns([
264
- columnHelper.accessor('firstName', {
265
- /* … */
266
- }),
267
- columnHelper.accessor('lastName', {
268
- /* … */
269
- }),
270
- ])
271
- function App() {
272
- const [columns] = React.useState(() => [...defaultColumns])
273
- const table = useTable({ features, columns, data })
274
- }
275
-
276
- // or: useMemo
277
- const columns = React.useMemo(
278
- () =>
279
- columnHelper.columns([
280
- /* … */
281
- ]),
282
- [],
283
- )
284
- ```
285
-
286
- Layout features commit state on every interaction. An inline `columns` array gets a new identity each render → table rebuild → another render. FAQ Pitfall 1.
287
-
288
- Source: docs/faq.md; examples/react/column-pinning-split/src/main.tsx; examples/react/column-dnd/src/main.tsx
289
-
290
- ### [CRITICAL] Reimplementing visibility / pinning / resize logic manually
291
-
292
- Wrong:
293
-
294
- ```ts
295
- // Hand-rolled hide/show with a separate set
296
- const [hidden, setHidden] = useState(new Set<string>())
297
- const visibleColumns = useMemo(
298
- () => columns.filter((c) => !hidden.has(c.id)),
299
- [columns, hidden],
300
- )
301
- ```
302
-
303
- Correct:
304
-
305
- ```ts
306
- const table = useTable({
307
- features: tableFeatures({ columnVisibilityFeature }),
308
- columns,
309
- data,
310
- })
311
- column.toggleVisibility()
312
- column.getIsVisible()
313
- table.getVisibleLeafColumns()
314
- ```
315
-
316
- Source: maintainer interview (Phase 4, 2026-05-17)
317
-
318
- ## See also
319
-
320
- - `tanstack-table/state-management` — `state.columnVisibility` / `columnOrder` / `columnPinning` / `columnSizing` slices
321
- - `tanstack-table/row-pinning` — analogous pinning for rows (different render pipeline)
322
- - `tanstack-table/grouping` — `groupedColumnMode` interacts with `columnOrder`
323
-
324
- ## References
325
-
326
- - [subsystems.md](references/subsystems.md) — full API surface per UI-state subsystem (visibility, ordering, pinning, sizing, resizing) plus MEDIUM-priority failure modes: reorder-pinned-via-`columnOrder`, react-dnd / react-beautiful-dnd avoidance, touch-resize handler
@@ -1,220 +0,0 @@
1
- # Column-layout subsystems — full API surface
2
-
3
- Detailed reference for the five UI-state-only column features extracted from `SKILL.md`. The SKILL keeps a 2-line summary table linking here; this file documents each subsystem in detail.
4
-
5
- ## Visibility — `columnVisibilityFeature`
6
-
7
- State: `columnVisibility: Record<columnId, boolean>` — missing or `true` means visible.
8
-
9
- ```tsx
10
- // Visibility toggle panel
11
- {
12
- table.getAllLeafColumns().map((column) => (
13
- <label key={column.id}>
14
- <input
15
- type="checkbox"
16
- checked={column.getIsVisible()}
17
- disabled={!column.getCanHide()}
18
- onChange={column.getToggleVisibilityHandler()}
19
- />
20
- {column.id}
21
- </label>
22
- ))
23
- }
24
-
25
- // Body — use Visible variants, NOT getAllLeafColumns / getAllCells
26
- ;<tbody>
27
- {table.getRowModel().rows.map((row) => (
28
- <tr key={row.id}>
29
- {row.getVisibleCells().map((cell) => (
30
- <td key={cell.id}>
31
- <table.FlexRender cell={cell} />
32
- </td>
33
- ))}
34
- </tr>
35
- ))}
36
- </tbody>
37
- ```
38
-
39
- ## Ordering — `columnOrderingFeature`
40
-
41
- State: `columnOrder: string[]` of leaf column ids. Empty means definition order. **Scoped to UNPINNED columns** when pinning is active — pinned columns are sequenced inside `columnPinning.left/right`.
42
-
43
- ```ts
44
- table.setColumnOrder(['firstName', 'lastName', 'age'])
45
- column.getIndex('center') // ← position
46
- column.getIsFirstColumn()
47
- column.getIsLastColumn()
48
- ```
49
-
50
- For drag-and-drop with `@dnd-kit/core`, see the "Common Mistakes" entry on dnd libraries in the SKILL — `DndContext` must wrap from OUTSIDE the `<table>`.
51
-
52
- ## Pinning — `columnPinningFeature`
53
-
54
- State: `columnPinning: { left: string[]; right: string[] }`. Two render strategies:
55
-
56
- ```tsx
57
- // Strategy A — split tables
58
- <thead>
59
- {table.getLeftHeaderGroups().map(/* … */)}
60
- </thead>
61
- // + getCenterHeaderGroups / getRightHeaderGroups
62
- // + row.getLeftVisibleCells / getCenterVisibleCells / getRightVisibleCells
63
-
64
- // Strategy B — single table + sticky CSS
65
- <th
66
- key={header.id}
67
- style={{
68
- position: header.column.getIsPinned() ? 'sticky' : undefined,
69
- left: header.column.getIsPinned() === 'left' ? `${header.column.getStart('left')}px` : undefined,
70
- right: header.column.getIsPinned() === 'right' ? `${header.column.getAfter('right')}px` : undefined,
71
- }}
72
- >
73
- ...
74
- </th>
75
-
76
- // Toggle a pin programmatically
77
- column.pin('left') // or 'right' | false
78
- ```
79
-
80
- ## Sizing — `columnSizingFeature`
81
-
82
- State: `columnSizing: Record<columnId, number>` (pixels). Defaults via `defaultColumnSizing` ({ size: 150, minSize: 20, maxSize: Number.MAX_SAFE_INTEGER }) or `tableOptions.defaultColumn` globally.
83
-
84
- ```ts
85
- columnHelper.accessor('firstName', {
86
- size: 200,
87
- minSize: 80,
88
- maxSize: 400,
89
- })
90
-
91
- // Reads
92
- column.getSize() // committed size (clamped)
93
- header.getSize() // same, for groups sums children
94
- table.getTotalSize()
95
- table.getCenterTotalSize()
96
- column.resetSize() // drop the override
97
- ```
98
-
99
- ## Resizing — `columnResizingFeature`
100
-
101
- ```tsx
102
- // Wire BOTH onMouseDown AND onTouchStart on the resize handle
103
- <div
104
- onDoubleClick={() => header.column.resetSize()}
105
- onMouseDown={header.getResizeHandler()}
106
- onTouchStart={header.getResizeHandler()}
107
- className={`resizer ${header.column.getIsResizing() ? 'isResizing' : ''}`}
108
- />
109
-
110
- // Modes:
111
- // columnResizeMode: 'onEnd' (default) — commit on drag release; safer for big React tables
112
- // columnResizeMode: 'onChange' — commit live; needs the perf pattern in SKILL
113
- // columnResizeDirection: 'ltr' (default) | 'rtl'
114
- ```
115
-
116
- ## Additional MEDIUM-priority failure modes
117
-
118
- ### Trying to reorder pinned columns via `columnOrder`
119
-
120
- Wrong:
121
-
122
- ```ts
123
- // Won't move 'actions' relative to 'firstName' while it's pinned right
124
- const [columnPinning] = useState({
125
- left: ['select'],
126
- right: ['actions'],
127
- })
128
- table.setColumnOrder(['actions', 'select', 'firstName', 'lastName'])
129
- ```
130
-
131
- Correct:
132
-
133
- ```ts
134
- // Reorder the pinning state itself
135
- table.setColumnPinning((old) => ({
136
- left: ['select'],
137
- right: ['summary', 'actions'], // 'summary' renders before 'actions'
138
- }))
139
-
140
- // columnOrder works normally for the unpinned center region
141
- table.setColumnOrder(['firstName', 'lastName'])
142
- ```
143
-
144
- After the pipeline's pinning split, the left/right partitions read directly from `state.columnPinning.left/right`. `columnOrder` only affects the center.
145
-
146
- Source: docs/guide/column-ordering.md; packages/table-core/src/features/column-pinning/columnPinningFeature.utils.ts
147
-
148
- ### Using `react-dnd` / `react-beautiful-dnd` for column reorder in React 18+
149
-
150
- Wrong:
151
-
152
- ```tsx
153
- // react-dnd in React 18 Strict Mode — flicker and stale drags
154
- import { DndProvider } from 'react-dnd'
155
- import { HTML5Backend } from 'react-dnd-html5-backend'
156
-
157
- // or nesting DndContext inside <table>
158
- ;<table>
159
- <DndContext onDragEnd={handleDragEnd}>
160
- <thead>...</thead>
161
- </DndContext>
162
- </table>
163
- ```
164
-
165
- Correct:
166
-
167
- ```tsx
168
- // @dnd-kit + wrap from OUTSIDE the table (DndContext renders divs)
169
- <DndContext
170
- collisionDetection={closestCenter}
171
- modifiers={[restrictToHorizontalAxis]}
172
- onDragEnd={handleDragEnd}
173
- sensors={sensors}
174
- >
175
- <table>
176
- <thead>
177
- {table.getHeaderGroups().map((hg) => (
178
- <tr key={hg.id}>
179
- <SortableContext
180
- items={table.store.state.columnOrder}
181
- strategy={horizontalListSortingStrategy}
182
- >
183
- {hg.headers.map((h) => (
184
- <DraggableHeader key={h.id} header={h} />
185
- ))}
186
- </SortableContext>
187
- </tr>
188
- ))}
189
- </thead>
190
- </table>
191
- </DndContext>
192
- ```
193
-
194
- `react-dnd` has Strict Mode incompatibilities; `react-beautiful-dnd` is in maintenance. dnd-kit is the v9-recommended stack.
195
-
196
- Source: examples/react/column-dnd/src/main.tsx
197
-
198
- ### Wiring `header.getResizeHandler()` to only `onMouseDown`
199
-
200
- Wrong:
201
-
202
- ```tsx
203
- // Desktop only — mobile users can't resize
204
- <div onMouseDown={header.getResizeHandler()} />
205
- ```
206
-
207
- Correct:
208
-
209
- ```tsx
210
- <div
211
- onDoubleClick={() => header.column.resetSize()}
212
- onMouseDown={header.getResizeHandler()}
213
- onTouchStart={header.getResizeHandler()}
214
- className={`resizer ${header.column.getIsResizing() ? 'isResizing' : ''}`}
215
- />
216
- ```
217
-
218
- `header_getResizeHandler` branches internally on `isTouchStartEvent`. The same handler must be installed on both DOM events.
219
-
220
- Source: docs/guide/column-resizing.md; examples/react/column-resizing/src/main.tsx