@tanstack/table-core 9.0.0-alpha.47 → 9.0.0-alpha.49

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 (246) hide show
  1. package/README.md +10 -0
  2. package/dist/core/cells/coreCellsFeature.utils.cjs +11 -8
  3. package/dist/core/cells/coreCellsFeature.utils.cjs.map +1 -1
  4. package/dist/core/cells/coreCellsFeature.utils.d.cts +11 -8
  5. package/dist/core/cells/coreCellsFeature.utils.d.ts +11 -8
  6. package/dist/core/cells/coreCellsFeature.utils.js +11 -8
  7. package/dist/core/cells/coreCellsFeature.utils.js.map +1 -1
  8. package/dist/core/columns/coreColumnsFeature.types.d.cts +7 -6
  9. package/dist/core/columns/coreColumnsFeature.types.d.ts +7 -6
  10. package/dist/core/columns/coreColumnsFeature.utils.cjs +37 -27
  11. package/dist/core/columns/coreColumnsFeature.utils.cjs.map +1 -1
  12. package/dist/core/columns/coreColumnsFeature.utils.d.cts +37 -27
  13. package/dist/core/columns/coreColumnsFeature.utils.d.ts +37 -27
  14. package/dist/core/columns/coreColumnsFeature.utils.js +37 -27
  15. package/dist/core/columns/coreColumnsFeature.utils.js.map +1 -1
  16. package/dist/core/headers/coreHeadersFeature.types.d.cts +6 -4
  17. package/dist/core/headers/coreHeadersFeature.types.d.ts +6 -4
  18. package/dist/core/headers/coreHeadersFeature.utils.cjs +23 -18
  19. package/dist/core/headers/coreHeadersFeature.utils.cjs.map +1 -1
  20. package/dist/core/headers/coreHeadersFeature.utils.d.cts +23 -18
  21. package/dist/core/headers/coreHeadersFeature.utils.d.ts +23 -18
  22. package/dist/core/headers/coreHeadersFeature.utils.js +23 -18
  23. package/dist/core/headers/coreHeadersFeature.utils.js.map +1 -1
  24. package/dist/core/row-models/coreRowModelsFeature.utils.cjs +48 -36
  25. package/dist/core/row-models/coreRowModelsFeature.utils.cjs.map +1 -1
  26. package/dist/core/row-models/coreRowModelsFeature.utils.d.cts +48 -36
  27. package/dist/core/row-models/coreRowModelsFeature.utils.d.ts +48 -36
  28. package/dist/core/row-models/coreRowModelsFeature.utils.js +48 -36
  29. package/dist/core/row-models/coreRowModelsFeature.utils.js.map +1 -1
  30. package/dist/core/rows/coreRowsFeature.types.d.cts +4 -4
  31. package/dist/core/rows/coreRowsFeature.types.d.ts +4 -4
  32. package/dist/core/rows/coreRowsFeature.utils.cjs +34 -28
  33. package/dist/core/rows/coreRowsFeature.utils.cjs.map +1 -1
  34. package/dist/core/rows/coreRowsFeature.utils.d.cts +34 -28
  35. package/dist/core/rows/coreRowsFeature.utils.d.ts +34 -28
  36. package/dist/core/rows/coreRowsFeature.utils.js +34 -28
  37. package/dist/core/rows/coreRowsFeature.utils.js.map +1 -1
  38. package/dist/core/table/coreTablesFeature.types.d.cts +6 -2
  39. package/dist/core/table/coreTablesFeature.types.d.ts +6 -2
  40. package/dist/core/table/coreTablesFeature.utils.cjs +2 -2
  41. package/dist/core/table/coreTablesFeature.utils.cjs.map +1 -1
  42. package/dist/core/table/coreTablesFeature.utils.d.cts +2 -2
  43. package/dist/core/table/coreTablesFeature.utils.d.ts +2 -2
  44. package/dist/core/table/coreTablesFeature.utils.js +2 -2
  45. package/dist/core/table/coreTablesFeature.utils.js.map +1 -1
  46. package/dist/features/column-faceting/columnFacetingFeature.types.d.cts +16 -10
  47. package/dist/features/column-faceting/columnFacetingFeature.types.d.ts +16 -10
  48. package/dist/features/column-faceting/columnFacetingFeature.utils.cjs +26 -18
  49. package/dist/features/column-faceting/columnFacetingFeature.utils.cjs.map +1 -1
  50. package/dist/features/column-faceting/columnFacetingFeature.utils.d.cts +26 -18
  51. package/dist/features/column-faceting/columnFacetingFeature.utils.d.ts +26 -18
  52. package/dist/features/column-faceting/columnFacetingFeature.utils.js +26 -18
  53. package/dist/features/column-faceting/columnFacetingFeature.utils.js.map +1 -1
  54. package/dist/features/column-filtering/columnFilteringFeature.types.d.cts +21 -11
  55. package/dist/features/column-filtering/columnFilteringFeature.types.d.ts +21 -11
  56. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs +39 -28
  57. package/dist/features/column-filtering/columnFilteringFeature.utils.cjs.map +1 -1
  58. package/dist/features/column-filtering/columnFilteringFeature.utils.d.cts +39 -28
  59. package/dist/features/column-filtering/columnFilteringFeature.utils.d.ts +39 -28
  60. package/dist/features/column-filtering/columnFilteringFeature.utils.js +39 -28
  61. package/dist/features/column-filtering/columnFilteringFeature.utils.js.map +1 -1
  62. package/dist/features/column-grouping/columnGroupingFeature.types.d.cts +18 -14
  63. package/dist/features/column-grouping/columnGroupingFeature.types.d.ts +18 -14
  64. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs +55 -43
  65. package/dist/features/column-grouping/columnGroupingFeature.utils.cjs.map +1 -1
  66. package/dist/features/column-grouping/columnGroupingFeature.utils.d.cts +55 -43
  67. package/dist/features/column-grouping/columnGroupingFeature.utils.d.ts +55 -43
  68. package/dist/features/column-grouping/columnGroupingFeature.utils.js +55 -43
  69. package/dist/features/column-grouping/columnGroupingFeature.utils.js.map +1 -1
  70. package/dist/features/column-ordering/columnOrderingFeature.types.d.cts +14 -5
  71. package/dist/features/column-ordering/columnOrderingFeature.types.d.ts +14 -5
  72. package/dist/features/column-ordering/columnOrderingFeature.utils.cjs +30 -23
  73. package/dist/features/column-ordering/columnOrderingFeature.utils.cjs.map +1 -1
  74. package/dist/features/column-ordering/columnOrderingFeature.utils.d.cts +30 -23
  75. package/dist/features/column-ordering/columnOrderingFeature.utils.d.ts +30 -23
  76. package/dist/features/column-ordering/columnOrderingFeature.utils.js +30 -23
  77. package/dist/features/column-ordering/columnOrderingFeature.utils.js.map +1 -1
  78. package/dist/features/column-pinning/columnPinningFeature.types.d.cts +43 -31
  79. package/dist/features/column-pinning/columnPinningFeature.types.d.ts +43 -31
  80. package/dist/features/column-pinning/columnPinningFeature.utils.cjs +111 -91
  81. package/dist/features/column-pinning/columnPinningFeature.utils.cjs.map +1 -1
  82. package/dist/features/column-pinning/columnPinningFeature.utils.d.cts +111 -91
  83. package/dist/features/column-pinning/columnPinningFeature.utils.d.ts +111 -91
  84. package/dist/features/column-pinning/columnPinningFeature.utils.js +111 -91
  85. package/dist/features/column-pinning/columnPinningFeature.utils.js.map +1 -1
  86. package/dist/features/column-resizing/columnResizingFeature.types.d.cts +9 -9
  87. package/dist/features/column-resizing/columnResizingFeature.types.d.ts +9 -9
  88. package/dist/features/column-resizing/columnResizingFeature.utils.cjs +29 -20
  89. package/dist/features/column-resizing/columnResizingFeature.utils.cjs.map +1 -1
  90. package/dist/features/column-resizing/columnResizingFeature.utils.d.cts +28 -19
  91. package/dist/features/column-resizing/columnResizingFeature.utils.d.ts +28 -19
  92. package/dist/features/column-resizing/columnResizingFeature.utils.js +29 -20
  93. package/dist/features/column-resizing/columnResizingFeature.utils.js.map +1 -1
  94. package/dist/features/column-sizing/columnSizingFeature.types.d.cts +19 -12
  95. package/dist/features/column-sizing/columnSizingFeature.types.d.ts +19 -12
  96. package/dist/features/column-sizing/columnSizingFeature.utils.cjs +52 -41
  97. package/dist/features/column-sizing/columnSizingFeature.utils.cjs.map +1 -1
  98. package/dist/features/column-sizing/columnSizingFeature.utils.d.cts +52 -41
  99. package/dist/features/column-sizing/columnSizingFeature.utils.d.ts +52 -41
  100. package/dist/features/column-sizing/columnSizingFeature.utils.js +52 -41
  101. package/dist/features/column-sizing/columnSizingFeature.utils.js.map +1 -1
  102. package/dist/features/column-visibility/columnVisibilityFeature.types.d.cts +16 -13
  103. package/dist/features/column-visibility/columnVisibilityFeature.types.d.ts +16 -13
  104. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs +54 -42
  105. package/dist/features/column-visibility/columnVisibilityFeature.utils.cjs.map +1 -1
  106. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.cts +54 -42
  107. package/dist/features/column-visibility/columnVisibilityFeature.utils.d.ts +54 -42
  108. package/dist/features/column-visibility/columnVisibilityFeature.utils.js +54 -42
  109. package/dist/features/column-visibility/columnVisibilityFeature.utils.js.map +1 -1
  110. package/dist/features/global-filtering/globalFilteringFeature.types.d.cts +10 -5
  111. package/dist/features/global-filtering/globalFilteringFeature.types.d.ts +10 -5
  112. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs +20 -14
  113. package/dist/features/global-filtering/globalFilteringFeature.utils.cjs.map +1 -1
  114. package/dist/features/global-filtering/globalFilteringFeature.utils.d.cts +20 -14
  115. package/dist/features/global-filtering/globalFilteringFeature.utils.d.ts +20 -14
  116. package/dist/features/global-filtering/globalFilteringFeature.utils.js +20 -14
  117. package/dist/features/global-filtering/globalFilteringFeature.utils.js.map +1 -1
  118. package/dist/features/row-expanding/rowExpandingFeature.types.d.cts +16 -15
  119. package/dist/features/row-expanding/rowExpandingFeature.types.d.ts +16 -15
  120. package/dist/features/row-expanding/rowExpandingFeature.utils.cjs +56 -41
  121. package/dist/features/row-expanding/rowExpandingFeature.utils.cjs.map +1 -1
  122. package/dist/features/row-expanding/rowExpandingFeature.utils.d.cts +56 -41
  123. package/dist/features/row-expanding/rowExpandingFeature.utils.d.ts +56 -41
  124. package/dist/features/row-expanding/rowExpandingFeature.utils.js +56 -41
  125. package/dist/features/row-expanding/rowExpandingFeature.utils.js.map +1 -1
  126. package/dist/features/row-pagination/rowPaginationFeature.types.d.cts +19 -12
  127. package/dist/features/row-pagination/rowPaginationFeature.types.d.ts +19 -12
  128. package/dist/features/row-pagination/rowPaginationFeature.utils.cjs +49 -32
  129. package/dist/features/row-pagination/rowPaginationFeature.utils.cjs.map +1 -1
  130. package/dist/features/row-pagination/rowPaginationFeature.utils.d.cts +49 -32
  131. package/dist/features/row-pagination/rowPaginationFeature.utils.d.ts +49 -32
  132. package/dist/features/row-pagination/rowPaginationFeature.utils.js +49 -32
  133. package/dist/features/row-pagination/rowPaginationFeature.utils.js.map +1 -1
  134. package/dist/features/row-pinning/rowPinningFeature.types.d.cts +12 -8
  135. package/dist/features/row-pinning/rowPinningFeature.types.d.ts +12 -8
  136. package/dist/features/row-pinning/rowPinningFeature.utils.cjs +39 -29
  137. package/dist/features/row-pinning/rowPinningFeature.utils.cjs.map +1 -1
  138. package/dist/features/row-pinning/rowPinningFeature.utils.d.cts +39 -29
  139. package/dist/features/row-pinning/rowPinningFeature.utils.d.ts +39 -29
  140. package/dist/features/row-pinning/rowPinningFeature.utils.js +39 -29
  141. package/dist/features/row-pinning/rowPinningFeature.utils.js.map +1 -1
  142. package/dist/features/row-selection/rowSelectionFeature.types.d.cts +30 -24
  143. package/dist/features/row-selection/rowSelectionFeature.types.d.ts +30 -24
  144. package/dist/features/row-selection/rowSelectionFeature.utils.cjs +89 -69
  145. package/dist/features/row-selection/rowSelectionFeature.utils.cjs.map +1 -1
  146. package/dist/features/row-selection/rowSelectionFeature.utils.d.cts +89 -69
  147. package/dist/features/row-selection/rowSelectionFeature.utils.d.ts +89 -69
  148. package/dist/features/row-selection/rowSelectionFeature.utils.js +89 -69
  149. package/dist/features/row-selection/rowSelectionFeature.utils.js.map +1 -1
  150. package/dist/features/row-sorting/rowSortingFeature.types.d.cts +10 -8
  151. package/dist/features/row-sorting/rowSortingFeature.types.d.ts +10 -8
  152. package/dist/features/row-sorting/rowSortingFeature.utils.cjs +62 -45
  153. package/dist/features/row-sorting/rowSortingFeature.utils.cjs.map +1 -1
  154. package/dist/features/row-sorting/rowSortingFeature.utils.d.cts +61 -44
  155. package/dist/features/row-sorting/rowSortingFeature.utils.d.ts +61 -44
  156. package/dist/features/row-sorting/rowSortingFeature.utils.js +62 -45
  157. package/dist/features/row-sorting/rowSortingFeature.utils.js.map +1 -1
  158. package/dist/fns/aggregationFns.cjs +33 -9
  159. package/dist/fns/aggregationFns.cjs.map +1 -1
  160. package/dist/fns/aggregationFns.d.cts +33 -9
  161. package/dist/fns/aggregationFns.d.ts +33 -9
  162. package/dist/fns/aggregationFns.js +33 -9
  163. package/dist/fns/aggregationFns.js.map +1 -1
  164. package/dist/fns/filterFns.cjs +48 -17
  165. package/dist/fns/filterFns.cjs.map +1 -1
  166. package/dist/fns/filterFns.d.cts +42 -15
  167. package/dist/fns/filterFns.d.ts +42 -15
  168. package/dist/fns/filterFns.js +48 -17
  169. package/dist/fns/filterFns.js.map +1 -1
  170. package/dist/helpers/columnHelper.cjs +9 -4
  171. package/dist/helpers/columnHelper.cjs.map +1 -1
  172. package/dist/helpers/columnHelper.d.cts +9 -4
  173. package/dist/helpers/columnHelper.d.ts +9 -4
  174. package/dist/helpers/columnHelper.js +9 -4
  175. package/dist/helpers/columnHelper.js.map +1 -1
  176. package/dist/helpers/tableOptions.cjs.map +1 -1
  177. package/dist/helpers/tableOptions.d.cts +12 -9
  178. package/dist/helpers/tableOptions.d.ts +12 -9
  179. package/dist/helpers/tableOptions.js.map +1 -1
  180. package/dist/types/ColumnDef.d.cts +38 -0
  181. package/dist/types/ColumnDef.d.ts +38 -0
  182. package/dist/types/TableOptions.d.cts +15 -0
  183. package/dist/types/TableOptions.d.ts +15 -0
  184. package/dist/types/TableState.d.cts +12 -0
  185. package/dist/types/TableState.d.ts +12 -0
  186. package/package.json +5 -3
  187. package/skills/column-definitions/SKILL.md +333 -0
  188. package/skills/column-layout/SKILL.md +328 -0
  189. package/skills/column-layout/references/subsystems.md +220 -0
  190. package/skills/customizing-feature-behavior/SKILL.md +416 -0
  191. package/skills/filtering/SKILL.md +357 -0
  192. package/skills/filtering/references/faceting-and-fuzzy.md +191 -0
  193. package/skills/grouping/SKILL.md +448 -0
  194. package/skills/migrate-v8-to-v9/SKILL.md +495 -0
  195. package/skills/pagination/SKILL.md +385 -0
  196. package/skills/row-expanding/SKILL.md +348 -0
  197. package/skills/row-pinning/SKILL.md +269 -0
  198. package/skills/row-selection/SKILL.md +391 -0
  199. package/skills/setup/SKILL.md +400 -0
  200. package/skills/sorting/SKILL.md +344 -0
  201. package/skills/state-management/SKILL.md +388 -0
  202. package/src/core/cells/coreCellsFeature.utils.ts +11 -8
  203. package/src/core/columns/coreColumnsFeature.types.ts +7 -6
  204. package/src/core/columns/coreColumnsFeature.utils.ts +37 -27
  205. package/src/core/headers/coreHeadersFeature.types.ts +6 -4
  206. package/src/core/headers/coreHeadersFeature.utils.ts +23 -18
  207. package/src/core/row-models/coreRowModelsFeature.utils.ts +48 -36
  208. package/src/core/rows/coreRowsFeature.types.ts +4 -4
  209. package/src/core/rows/coreRowsFeature.utils.ts +34 -28
  210. package/src/core/table/coreTablesFeature.types.ts +6 -2
  211. package/src/core/table/coreTablesFeature.utils.ts +2 -2
  212. package/src/features/column-faceting/columnFacetingFeature.types.ts +16 -10
  213. package/src/features/column-faceting/columnFacetingFeature.utils.ts +26 -18
  214. package/src/features/column-filtering/columnFilteringFeature.types.ts +21 -11
  215. package/src/features/column-filtering/columnFilteringFeature.utils.ts +39 -28
  216. package/src/features/column-grouping/columnGroupingFeature.types.ts +18 -14
  217. package/src/features/column-grouping/columnGroupingFeature.utils.ts +55 -43
  218. package/src/features/column-ordering/columnOrderingFeature.types.ts +14 -5
  219. package/src/features/column-ordering/columnOrderingFeature.utils.ts +30 -23
  220. package/src/features/column-pinning/columnPinningFeature.types.ts +43 -31
  221. package/src/features/column-pinning/columnPinningFeature.utils.ts +111 -91
  222. package/src/features/column-resizing/columnResizingFeature.types.ts +9 -9
  223. package/src/features/column-resizing/columnResizingFeature.utils.ts +29 -21
  224. package/src/features/column-sizing/columnSizingFeature.types.ts +19 -12
  225. package/src/features/column-sizing/columnSizingFeature.utils.ts +52 -41
  226. package/src/features/column-visibility/columnVisibilityFeature.types.ts +16 -13
  227. package/src/features/column-visibility/columnVisibilityFeature.utils.ts +54 -42
  228. package/src/features/global-filtering/globalFilteringFeature.types.ts +10 -5
  229. package/src/features/global-filtering/globalFilteringFeature.utils.ts +20 -14
  230. package/src/features/row-expanding/rowExpandingFeature.types.ts +16 -15
  231. package/src/features/row-expanding/rowExpandingFeature.utils.ts +56 -41
  232. package/src/features/row-pagination/rowPaginationFeature.types.ts +19 -12
  233. package/src/features/row-pagination/rowPaginationFeature.utils.ts +49 -32
  234. package/src/features/row-pinning/rowPinningFeature.types.ts +12 -8
  235. package/src/features/row-pinning/rowPinningFeature.utils.ts +39 -29
  236. package/src/features/row-selection/rowSelectionFeature.types.ts +30 -24
  237. package/src/features/row-selection/rowSelectionFeature.utils.ts +89 -69
  238. package/src/features/row-sorting/rowSortingFeature.types.ts +10 -8
  239. package/src/features/row-sorting/rowSortingFeature.utils.ts +62 -45
  240. package/src/fns/aggregationFns.ts +33 -9
  241. package/src/fns/filterFns.ts +48 -17
  242. package/src/helpers/columnHelper.ts +9 -4
  243. package/src/helpers/tableOptions.ts +12 -9
  244. package/src/types/ColumnDef.ts +38 -0
  245. package/src/types/TableOptions.ts +15 -0
  246. package/src/types/TableState.ts +12 -0
@@ -0,0 +1,220 @@
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
@@ -0,0 +1,416 @@
1
+ ---
2
+ name: customizing-feature-behavior
3
+ description: >
4
+ Override per-column `sortFn`, `filterFn`, `aggregationFn` and table-level
5
+ `globalFilterFn` in TanStack Table v9. Covers built-in `filterFns` / `sortFns` /
6
+ `aggregationFns` registries (passed to `createFilteredRowModel(filterFns)` /
7
+ `createSortedRowModel(sortFns)` / `createGroupedRowModel(aggregationFns)`),
8
+ authoring custom functions with the `FilterFn` / `SortFn` / `AggregationFn`
9
+ signatures, chaining filter→sort via the `addMeta` callback +
10
+ `row.columnFiltersMeta`, `resolveFilterValue`, `autoRemove`, `invertSorting`,
11
+ `sortUndefined` ('first'|'last'|-1|1), and `sortDescFirst`. Distinguishes
12
+ `aggregationFn` (produces value) from `aggregatedCell` (renders value).
13
+ type: core
14
+ library: tanstack-table
15
+ library_version: '9.0.0-alpha.48'
16
+ requires:
17
+ - state-management
18
+ sources:
19
+ - TanStack/table:docs/guide/sorting.md
20
+ - TanStack/table:docs/guide/column-filtering.md
21
+ - TanStack/table:docs/guide/fuzzy-filtering.md
22
+ - TanStack/table:packages/table-core/src/fns/filterFns.ts
23
+ - TanStack/table:packages/table-core/src/fns/sortFns.ts
24
+ - TanStack/table:packages/table-core/src/fns/aggregationFns.ts
25
+ - TanStack/table:examples/react/filters-fuzzy/src/main.tsx
26
+ ---
27
+
28
+ This skill builds on `tanstack-table/state-management`. Read it first for how feature plugins drive state slices.
29
+
30
+ ## Setup
31
+
32
+ v9 customization happens in three places:
33
+
34
+ 1. **Built-in function registries** — `filterFns`, `sortFns`, `aggregationFns` — passed as arguments to row-model factories so unused fns tree-shake away.
35
+ 2. **Per-column overrides** — `columnDef.filterFn`, `columnDef.sortFn`, `columnDef.aggregationFn` (string name OR inline function).
36
+ 3. **Table-level overrides** — `tableOptions.globalFilterFn`.
37
+
38
+ ```ts
39
+ import {
40
+ tableFeatures,
41
+ rowSortingFeature,
42
+ columnFilteringFeature,
43
+ globalFilteringFeature,
44
+ columnGroupingFeature,
45
+ rowExpandingFeature,
46
+ createFilteredRowModel,
47
+ createSortedRowModel,
48
+ createGroupedRowModel,
49
+ createExpandedRowModel,
50
+ filterFns,
51
+ sortFns,
52
+ aggregationFns,
53
+ createColumnHelper,
54
+ } from '@tanstack/table-core'
55
+ import type { FilterFn, SortFn, AggregationFn } from '@tanstack/table-core'
56
+ import {
57
+ rankItem,
58
+ compareItems,
59
+ type RankingInfo,
60
+ } from '@tanstack/match-sorter-utils'
61
+
62
+ type Person = {
63
+ id: string
64
+ firstName: string
65
+ lastName: string
66
+ revenue: number
67
+ status: 'single' | 'complicated' | 'relationship'
68
+ }
69
+
70
+ const _features = tableFeatures({
71
+ rowSortingFeature,
72
+ columnFilteringFeature,
73
+ globalFilteringFeature,
74
+ columnGroupingFeature,
75
+ rowExpandingFeature,
76
+ })
77
+
78
+ // Module augmentation registers custom fn names so columnDef.filterFn typechecks.
79
+ declare module '@tanstack/table-core' {
80
+ interface FilterFns {
81
+ fuzzy: FilterFn<typeof _features, Person>
82
+ }
83
+ interface FilterMeta {
84
+ itemRank?: RankingInfo
85
+ }
86
+ }
87
+
88
+ const fuzzyFilter: FilterFn<typeof _features, Person> = (
89
+ row,
90
+ columnId,
91
+ value,
92
+ addMeta,
93
+ ) => {
94
+ const itemRank = rankItem(row.getValue(columnId), value)
95
+ addMeta?.({ itemRank })
96
+ return itemRank.passed
97
+ }
98
+
99
+ const columnHelper = createColumnHelper<typeof _features, Person>()
100
+
101
+ const columns = columnHelper.columns([
102
+ columnHelper.accessor('firstName', {
103
+ filterFn: 'fuzzy', // ← refers to registered name
104
+ sortFn: 'alphanumeric',
105
+ }),
106
+ columnHelper.accessor('revenue', {
107
+ aggregationFn: 'sum',
108
+ aggregatedCell: (info) => `$${info.getValue<number>().toLocaleString()}`,
109
+ }),
110
+ ])
111
+
112
+ const table = constructTable({
113
+ _features,
114
+ _rowModels: {
115
+ filteredRowModel: createFilteredRowModel({
116
+ ...filterFns, // keep built-ins
117
+ fuzzy: fuzzyFilter, // add custom
118
+ }),
119
+ sortedRowModel: createSortedRowModel(sortFns),
120
+ groupedRowModel: createGroupedRowModel(aggregationFns),
121
+ expandedRowModel: createExpandedRowModel(),
122
+ },
123
+ columns,
124
+ data,
125
+ globalFilterFn: 'fuzzy',
126
+ })
127
+ ```
128
+
129
+ ## Core Patterns
130
+
131
+ ### Pick a built-in `sortFn` by name + direction control
132
+
133
+ ```ts
134
+ columnHelper.accessor('lastName', {
135
+ sortFn: 'alphanumeric',
136
+ sortDescFirst: false,
137
+ sortUndefined: 'last', // ABSOLUTE: always at end regardless of asc/desc
138
+ })
139
+ ```
140
+
141
+ Layered direction controls:
142
+
143
+ - `sortDescFirst: true/false` — first click sorts descending
144
+ - `sortUndefined: 'first' | 'last' | -1 | 1 | false` — string forms are absolute; numeric flips with `desc`
145
+ - `invertSorting: true` — for "lower-is-better" scales (rank 1 above rank 2 even when descending)
146
+
147
+ ### Filter → sort handoff via `addMeta`
148
+
149
+ ```ts
150
+ const fuzzyFilter: FilterFn<typeof _features, Person> = (
151
+ row,
152
+ columnId,
153
+ value,
154
+ addMeta,
155
+ ) => {
156
+ const itemRank = rankItem(row.getValue(columnId), value)
157
+ addMeta?.({ itemRank })
158
+ return itemRank.passed
159
+ }
160
+
161
+ // Custom sortFn reads the meta the filter stashed
162
+ const fuzzySort: SortFn<typeof _features, Person> = (rowA, rowB, columnId) => {
163
+ let dir = 0
164
+ if (rowA.columnFiltersMeta[columnId]) {
165
+ dir = compareItems(
166
+ rowA.columnFiltersMeta[columnId].itemRank!,
167
+ rowB.columnFiltersMeta[columnId].itemRank!,
168
+ )
169
+ }
170
+ return dir === 0 ? sortFns.alphanumeric(rowA, rowB, columnId) : dir
171
+ }
172
+
173
+ columnHelper.accessor('fullName', { filterFn: 'fuzzy', sortFn: fuzzySort })
174
+ ```
175
+
176
+ `row.columnFiltersMeta` is keyed by the column id that produced the meta (or `'__global__'` for the global filter). The sortFn MUST look up the same column id its filterFn used.
177
+
178
+ ### Custom `aggregationFn` for grouping
179
+
180
+ ```ts
181
+ import type { AggregationFn } from '@tanstack/table-core'
182
+
183
+ // Signature: (columnId, leafRows, childRows) → aggregated value
184
+ // leafRows = all descendant non-grouped rows
185
+ // childRows = immediate children (may be sub-aggregates at deeper levels)
186
+ const weightedMean: AggregationFn<typeof _features, Person> = (
187
+ columnId,
188
+ leafRows,
189
+ ) => {
190
+ let totalWeight = 0
191
+ let weightedSum = 0
192
+ leafRows.forEach((row) => {
193
+ const v = row.getValue<number>(columnId)
194
+ const w = row.original.revenue
195
+ weightedSum += v * w
196
+ totalWeight += w
197
+ })
198
+ return totalWeight === 0 ? 0 : weightedSum / totalWeight
199
+ }
200
+
201
+ const table = constructTable({
202
+ _features,
203
+ _rowModels: {
204
+ groupedRowModel: createGroupedRowModel({ ...aggregationFns, weightedMean }),
205
+ expandedRowModel: createExpandedRowModel(),
206
+ },
207
+ columns: columnHelper.columns([
208
+ columnHelper.accessor('revenue', {
209
+ aggregationFn: 'weightedMean',
210
+ aggregatedCell: (info) => `$${info.getValue<number>().toFixed(2)}`,
211
+ }),
212
+ ]),
213
+ data,
214
+ })
215
+ ```
216
+
217
+ ## Common Mistakes
218
+
219
+ ### [CRITICAL] Referencing a custom `filterFn` by string without registering it
220
+
221
+ Wrong:
222
+
223
+ ```ts
224
+ // "fuzzy" string never registered
225
+ const table = useTable({
226
+ _features,
227
+ columns: [columnHelper.accessor('fullName', { filterFn: 'fuzzy' })],
228
+ _rowModels: {
229
+ filteredRowModel: createFilteredRowModel(filterFns), // ❌ no fuzzy
230
+ },
231
+ data,
232
+ })
233
+ ```
234
+
235
+ Correct:
236
+
237
+ ```ts
238
+ declare module '@tanstack/react-table' {
239
+ interface FilterFns {
240
+ fuzzy: FilterFn<typeof _features, Person>
241
+ }
242
+ }
243
+
244
+ const fuzzyFilter: FilterFn<typeof _features, Person> = (
245
+ row,
246
+ columnId,
247
+ value,
248
+ addMeta,
249
+ ) => {
250
+ const itemRank = rankItem(row.getValue(columnId), value)
251
+ addMeta?.({ itemRank })
252
+ return itemRank.passed
253
+ }
254
+
255
+ const table = useTable({
256
+ _features,
257
+ columns: [columnHelper.accessor('fullName', { filterFn: 'fuzzy' })],
258
+ _rowModels: {
259
+ filteredRowModel: createFilteredRowModel({
260
+ ...filterFns,
261
+ fuzzy: fuzzyFilter,
262
+ }),
263
+ },
264
+ data,
265
+ })
266
+ ```
267
+
268
+ String values are looked up in `table._rowModelFns.filterFns`. Unregistered names log `Could not find a valid 'column.filterFn' …` in dev and silently no-op in prod.
269
+
270
+ Source: examples/react/filters-fuzzy/src/main.tsx; packages/table-core/src/features/column-filtering/columnFilteringFeature.utils.ts
271
+
272
+ ### [HIGH] Using v8 `sortingFn` / `sortingFns` names
273
+
274
+ Wrong:
275
+
276
+ ```ts
277
+ columnHelper.accessor('age', {
278
+ sortingFn: 'alphanumeric', // v8 name — ignored
279
+ })
280
+ ```
281
+
282
+ Correct:
283
+
284
+ ```ts
285
+ columnHelper.accessor('age', {
286
+ sortFn: 'alphanumeric',
287
+ })
288
+ ```
289
+
290
+ v9 renamed every sorting API: `sortingFn` → `sortFn`, `sortingFns` → `sortFns`, type `SortingFn` → `SortFn`, `column.getSortingFn()` → `column.getSortFn()`. The default `sortFn` is `'auto'`, falling back to `sortFn_basic` if the lookup misses — so wrong names sort wrong instead of erroring.
291
+
292
+ Source: docs/framework/react/guide/migrating.md; packages/table-core/src/features/row-sorting/rowSortingFeature.types.ts
293
+
294
+ ### [HIGH] Custom `sortFn` reads filter meta from a different column id
295
+
296
+ Wrong:
297
+
298
+ ```ts
299
+ // filter on 'fullName', sort reads meta from 'firstName'
300
+ const fuzzySort: SortFn<typeof _features, Person> = (a, b, columnId) => {
301
+ const meta = a.columnFiltersMeta['firstName'] // ❌ wrong key
302
+ return meta
303
+ ? compareItems(meta.itemRank, b.columnFiltersMeta['firstName'].itemRank)
304
+ : 0
305
+ }
306
+ columnHelper.accessor('fullName', { filterFn: 'fuzzy', sortFn: fuzzySort })
307
+ ```
308
+
309
+ Correct:
310
+
311
+ ```ts
312
+ const fuzzySort: SortFn<typeof _features, Person> = (rowA, rowB, columnId) => {
313
+ let dir = 0
314
+ if (rowA.columnFiltersMeta[columnId]) {
315
+ dir = compareItems(
316
+ rowA.columnFiltersMeta[columnId].itemRank!,
317
+ rowB.columnFiltersMeta[columnId].itemRank!,
318
+ )
319
+ }
320
+ return dir === 0 ? sortFns.alphanumeric(rowA, rowB, columnId) : dir
321
+ }
322
+ ```
323
+
324
+ `row.columnFiltersMeta` is keyed by the column id that produced it. Always use the `columnId` argument the sortFn receives.
325
+
326
+ Source: examples/react/filters-fuzzy/src/main.tsx
327
+
328
+ ### [MEDIUM] Returning a complex value from the accessor while using a built-in `sortFn`
329
+
330
+ Wrong:
331
+
332
+ ```ts
333
+ // accessor returns object; alphanumeric sees "[object Object]"
334
+ columnHelper.accessor((row) => row.name, {
335
+ id: 'name',
336
+ sortFn: 'alphanumeric',
337
+ })
338
+ ```
339
+
340
+ Correct:
341
+
342
+ ```ts
343
+ // Option A — return a primitive
344
+ columnHelper.accessor((row) => `${row.name.first} ${row.name.last}`, {
345
+ id: 'fullName',
346
+ sortFn: 'alphanumeric',
347
+ })
348
+
349
+ // Option B — custom sortFn that knows the shape
350
+ columnHelper.accessor((row) => row.name, {
351
+ id: 'name',
352
+ sortFn: (a, b, id) => {
353
+ const av = a.getValue<{ first: string }>(id).first
354
+ const bv = b.getValue<{ first: string }>(id).first
355
+ return av === bv ? 0 : av > bv ? 1 : -1
356
+ },
357
+ })
358
+ ```
359
+
360
+ Built-in sortFns (`alphanumeric`, `text`, `basic`) coerce via comparison operators. Object accessors collapse to `"[object Object]"` and every row ties.
361
+
362
+ Source: packages/table-core/src/fns/sortFns.ts
363
+
364
+ ### [MEDIUM] Confusing `aggregationFn` with `aggregatedCell`
365
+
366
+ Wrong:
367
+
368
+ ```ts
369
+ // rendering JSX inside the aggregation function
370
+ columnHelper.accessor('revenue', {
371
+ aggregationFn: (id, leaves) => <b>${leaves.reduce((a, r) => a + r.getValue(id), 0)}</b>,
372
+ })
373
+ ```
374
+
375
+ Correct:
376
+
377
+ ```ts
378
+ columnHelper.accessor('revenue', {
379
+ aggregationFn: 'sum', // returns a value
380
+ aggregatedCell: (info) => <b>${info.getValue<number>().toLocaleString()}</b>, // renders it
381
+ })
382
+ ```
383
+
384
+ `aggregationFn` produces the grouped-row value (signature `(columnId, leafRows, childRows)`). `aggregatedCell` renders it. Don't combine.
385
+
386
+ Source: packages/table-core/src/features/column-grouping/columnGroupingFeature.types.ts
387
+
388
+ ### [CRITICAL] Reimplementing what built-in APIs provide
389
+
390
+ Wrong:
391
+
392
+ ```ts
393
+ // Reimplements sorting state manually instead of using the API
394
+ const [sorting, setSorting] = useState([])
395
+ const sortedData = useMemo(() => [...data].sort(/* … */), [data, sorting])
396
+ ```
397
+
398
+ Correct:
399
+
400
+ ```ts
401
+ const table = useTable({
402
+ _features: tableFeatures({ rowSortingFeature }),
403
+ _rowModels: { sortedRowModel: createSortedRowModel(sortFns) },
404
+ columns,
405
+ data,
406
+ })
407
+ // table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler()
408
+ ```
409
+
410
+ Source: maintainer interview (Phase 4, 2026-05-17)
411
+
412
+ ## See also
413
+
414
+ - `tanstack-table/filtering` — `filterFn` placement, fuzzy filter pattern, faceted UI
415
+ - `tanstack-table/sorting` — built-in `sortFns`, multi-sort, `sortUndefined`
416
+ - `tanstack-table/grouping` — `aggregationFn` signature details and built-ins