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