@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,443 +1,99 @@
1
1
  ---
2
2
  name: grouping
3
3
  description: >
4
- Group rows by column values in TanStack Table v9 with the `groupedRowModel`
5
- stage. Covers `columnGroupingFeature` + `createGroupedRowModel()` (registered on `features` with `aggregationFns` slot),
6
- `state.grouping` (GroupingState = Array<string>), `onGroupingChange`,
7
- `columnDef.aggregationFn` ('auto'|name|fn) — distinct signature
8
- `(columnId, leafRows, childRows)` — `columnDef.aggregatedCell`,
9
- `columnDef.getGroupingValue`, `groupedColumnMode` (false|'reorder'|'remove'),
10
- `manualGrouping`, `column.toggleGrouping` / `getCanGroup` / `getIsGrouped`,
11
- `row.getIsGrouped` / `groupingColumnId` / `leafRows`, `cell.getIsGrouped` /
12
- `getIsAggregated` / `getIsPlaceholder`, the built-in `aggregationFns` registry,
13
- and the required `rowExpandingFeature` pairing for drill-down UX.
14
- type: core
15
- library: tanstack-table
16
- library_version: '9.0.0-alpha.48'
17
- requires:
18
- - state-management
19
- - customizing-feature-behavior
4
+ Group and aggregate rows with columnGroupingFeature, groupedRowModel, aggregationFns, groupedColumnMode, and manualGrouping. Load for grouped, placeholder, or aggregated cells and grouping interactions with expansion or pagination.
5
+ metadata:
6
+ {
7
+ type: sub-skill,
8
+ library: '@tanstack/table-core',
9
+ library_version: '9.0.0-beta.42',
10
+ }
11
+ requires: ['core', 'table-features', 'client-vs-server']
20
12
  sources:
21
- - TanStack/table:docs/guide/grouping.md
22
- - TanStack/table:packages/table-core/src/fns/aggregationFns.ts
23
- - TanStack/table:packages/table-core/src/features/column-grouping/createGroupedRowModel.ts
24
- - TanStack/table:examples/react/grouping/src/main.tsx
13
+ - 'TanStack/table:docs/framework/react/guide/grouping.md'
14
+ - 'TanStack/table:packages/table-core/src/features/column-grouping'
15
+ - 'TanStack/table:examples/react/grouping'
25
16
  ---
26
17
 
27
- This skill builds on `tanstack-table/state-management` and `tanstack-table/customizing-feature-behavior`. Read those first for the atom model and `aggregationFn` signature.
18
+ This skill builds on `core`, `table-features`, and `client-vs-server`. Grouping creates row structure and aggregate values; the renderer chooses grouped-cell UI.
28
19
 
29
20
  ## Setup
30
21
 
31
- Grouping nearly always pairs with expanding — otherwise grouped rows show aggregates with no way to drill in.
32
-
33
22
  ```ts
34
23
  import {
35
- tableFeatures,
24
+ aggregationFns,
36
25
  columnGroupingFeature,
37
- rowExpandingFeature,
38
- rowPaginationFeature,
39
26
  createGroupedRowModel,
40
- createExpandedRowModel,
41
- createPaginatedRowModel,
42
- aggregationFns,
43
- createColumnHelper,
44
- constructTable,
27
+ tableFeatures,
45
28
  } from '@tanstack/table-core'
46
- import type { GroupingState } from '@tanstack/table-core'
47
29
 
48
- const features = tableFeatures({
30
+ export const features = tableFeatures({
49
31
  columnGroupingFeature,
50
- rowExpandingFeature,
51
- rowPaginationFeature,
52
32
  groupedRowModel: createGroupedRowModel(),
53
- expandedRowModel: createExpandedRowModel(),
54
- paginatedRowModel: createPaginatedRowModel(),
55
33
  aggregationFns,
56
34
  })
57
-
58
- const columnHelper = createColumnHelper<typeof features, Person>()
59
-
60
- const columns = columnHelper.columns([
61
- columnHelper.accessor('firstName', {
62
- aggregatedCell: () => null,
63
- enableGrouping: false,
64
- }),
65
- columnHelper.accessor('age', { aggregationFn: 'median' }),
66
- columnHelper.accessor('visits', { aggregationFn: 'sum' }),
67
- columnHelper.accessor('status', { aggregationFn: 'count' }),
68
- columnHelper.accessor('progress', { aggregationFn: 'mean' }),
69
- ])
70
-
71
- const table = constructTable({
72
- features,
73
- columns,
74
- data,
75
- initialState: { grouping: [] satisfies GroupingState },
76
- })
77
-
78
- table.setGrouping(['status'])
79
35
  ```
80
36
 
81
37
  ## Core Patterns
82
38
 
83
- ### Per-column group toggle + aggregated cell rendering
84
-
85
- ```tsx
86
- // From examples/react/grouping/src/main.tsx
87
- {
88
- headerGroup.headers.map((header) => (
89
- <th key={header.id}>
90
- {header.column.getCanGroup() ? (
91
- <button onClick={header.column.getToggleGroupingHandler()}>
92
- {header.column.getIsGrouped()
93
- ? `🛑(${header.column.getGroupedIndex()}) `
94
- : '👊 '}
95
- </button>
96
- ) : null}
97
- <table.FlexRender header={header} />
98
- </th>
99
- ))
100
- }
101
-
102
- // Cell renderer with three branches: grouped, aggregated, normal
103
- {
104
- row.getVisibleCells().map((cell) => (
105
- <td key={cell.id}>
106
- {cell.getIsGrouped() ? (
107
- <>
108
- <button onClick={row.getToggleExpandedHandler()}>
109
- {row.getIsExpanded() ? '👇' : '👉'}
110
- </button>{' '}
111
- <table.FlexRender cell={cell} /> ({row.subRows.length})
112
- </>
113
- ) : cell.getIsAggregated() ? (
114
- <table.FlexRender cell={cell} />
115
- ) : cell.getIsPlaceholder() ? null : (
116
- <table.FlexRender cell={cell} />
117
- )}
118
- </td>
119
- ))
120
- }
121
- ```
122
-
123
- ### Custom `aggregationFn`
124
-
125
39
  ```ts
126
- import type { AggregationFn } from '@tanstack/table-core'
127
-
128
- // Signature: (columnId, leafRows, childRows) → aggregated value
129
- // leafRows = ALL descendant non-grouped rows (recursive)
130
- // childRows = immediate children (may themselves be sub-aggregates)
131
- const weightedAverage: AggregationFn<typeof features, Person> = (
132
- columnId,
133
- leafRows,
134
- ) => {
135
- let totalWeight = 0
136
- let weightedSum = 0
137
- leafRows.forEach((row) => {
138
- const v = row.getValue<number>(columnId)
139
- const w = row.original.weight
140
- weightedSum += v * w
141
- totalWeight += w
142
- })
143
- return totalWeight === 0 ? 0 : weightedSum / totalWeight
144
- }
145
-
146
- const customFeatures = tableFeatures({
147
- columnGroupingFeature,
148
- rowExpandingFeature,
149
- groupedRowModel: createGroupedRowModel(),
150
- expandedRowModel: createExpandedRowModel(),
151
- aggregationFns: { ...aggregationFns, weightedAverage },
152
- })
153
-
154
- const table = constructTable({
155
- features: customFeatures,
156
- columns: columnHelper.columns([
157
- columnHelper.accessor('progress', {
158
- aggregationFn: 'weightedAverage',
159
- aggregatedCell: (info) => `${info.getValue<number>().toFixed(1)}%`,
160
- }),
161
- ]),
162
- data,
163
- })
40
+ const options = { groupedColumnMode: 'reorder' as const }
41
+ const mode = cell.getIsGrouped()
42
+ ? 'grouped'
43
+ : cell.getIsAggregated()
44
+ ? 'aggregated'
45
+ : cell.getIsPlaceholder()
46
+ ? 'placeholder'
47
+ : 'value'
164
48
  ```
165
49
 
166
- ### Override grouping key with `getGroupingValue`
167
-
168
- ```ts
169
- columnHelper.accessor('firstName', {
170
- // group by full name, not just firstName
171
- getGroupingValue: (row) => `${row.firstName} ${row.lastName}`,
172
- })
173
- ```
174
-
175
- ### Control grouped-column placement
176
-
177
- ```ts
178
- const table = constructTable({
179
- features,
180
- columns,
181
- data,
182
- groupedColumnMode: 'reorder', // default — grouped columns lead
183
- // groupedColumnMode: 'remove', // hide grouped columns from visible flow
184
- // groupedColumnMode: false, // keep columnOrder intact
185
- })
186
- ```
50
+ Render these cell modes deliberately.
187
51
 
188
52
  ## Common Mistakes
189
53
 
190
- ### [HIGH] Adding `columnGroupingFeature` without `rowExpandingFeature`
191
-
192
- Wrong:
193
-
194
- ```ts
195
- // grouped rows show aggregates but can't be expanded
196
- const features = tableFeatures({
197
- columnGroupingFeature,
198
- groupedRowModel: createGroupedRowModel(),
199
- aggregationFns,
200
- })
201
- const table = useTable({ features, columns, data })
202
- // row.getToggleExpandedHandler() → TS error or undefined
203
- ```
204
-
205
- Correct:
206
-
207
- ```ts
208
- import {
209
- aggregationFns,
210
- columnGroupingFeature,
211
- createExpandedRowModel,
212
- createGroupedRowModel,
213
- rowExpandingFeature,
214
- } from '@tanstack/react-table'
215
-
216
- const features = tableFeatures({
217
- columnGroupingFeature,
218
- rowExpandingFeature,
219
- groupedRowModel: createGroupedRowModel(),
220
- expandedRowModel: createExpandedRowModel(),
221
- aggregationFns,
222
- })
223
-
224
- const table = useTable({ features, columns, data })
225
-
226
- // In cell renderer:
227
- {cell.getIsGrouped() && (
228
- <button onClick={row.getToggleExpandedHandler()}>
229
- {row.getIsExpanded() ? '👇' : '👉'} ({row.subRows.length})
230
- </button>
231
- )}
232
- ```
233
-
234
- Without `rowExpandingFeature`, `row.getToggleExpandedHandler` doesn't exist — grouped rows stay collapsed forever.
235
-
236
- Source: examples/react/grouping/src/main.tsx
237
-
238
- ### [HIGH] Customizing aggregationFns via a v8-style `tableOptions.aggregationFns` option
54
+ ### [HIGH] Registering processing without grouping
239
55
 
240
- Wrong:
56
+ Wrong: `tableFeatures({ groupedRowModel: createGroupedRowModel() })`
241
57
 
242
- ```ts
243
- const table = useTable({
244
- features: tableFeatures({
245
- columnGroupingFeature,
246
- groupedRowModel: createGroupedRowModel(),
247
- aggregationFns,
248
- }),
249
- columns, data,
250
- // @ts-ignore - this property doesn't exist on v9 TableOptions
251
- aggregationFns: {
252
- myCustom: (id, leaf, child) => /* ... */,
253
- },
254
- })
255
- ```
256
-
257
- Correct:
258
-
259
- ```ts
260
- import { aggregationFns, createGroupedRowModel } from '@tanstack/react-table'
261
-
262
- const features = tableFeatures({
263
- columnGroupingFeature,
264
- rowExpandingFeature,
265
- groupedRowModel: createGroupedRowModel(),
266
- expandedRowModel: createExpandedRowModel(),
267
- aggregationFns: {
268
- ...aggregationFns,
269
- myCustomAggregation: (columnId, leafRows, childRows) => {
270
- return /* aggregated value */
271
- },
272
- },
273
- })
274
-
275
- const table = useTable({ features, columns, data })
276
-
277
- // Then on a column:
278
- columnHelper.accessor('sales', { aggregationFn: 'myCustomAggregation' })
279
- ```
280
-
281
- In v9, the aggregation registry is the `aggregationFns` slot on `features`. There is no top-level `tableOptions.aggregationFns`.
282
-
283
- Source: packages/table-core/src/features/column-grouping/createGroupedRowModel.ts
284
-
285
- ### [MEDIUM] Confusing the `aggregationFn` signature with filter/sort signatures
286
-
287
- Wrong:
288
-
289
- ```ts
290
- // wrong arg names — first arg is columnId, not row
291
- aggregationFn: (rowA, rowB, columnId) => /* ... */
292
-
293
- // or: averaging via childRows includes already-aggregated sub-group sums
294
- aggregationFn: (id, leaf, child) => child.reduce((a, r) => a + r.getValue(id), 0) / child.length
295
- ```
296
-
297
- Correct:
298
-
299
- ```ts
300
- // (columnId, leafRows, childRows)
301
- // leafRows = all descendant non-grouped rows
302
- // childRows = immediate children (may be sub-aggregates)
303
-
304
- // For pure leaf averages, use leafRows:
305
- const aggregationFn_mean: AggregationFn<any, any> = (columnId, leafRows) => {
306
- let count = 0,
307
- sum = 0
308
- leafRows.forEach((row) => {
309
- const value = row.getValue(columnId)
310
- if (typeof value === 'number') {
311
- count++
312
- sum += value
313
- }
314
- })
315
- return count ? sum / count : undefined
316
- }
317
-
318
- // For nestable sums (reuse sub-aggregates), use childRows:
319
- const aggregationFn_sum: AggregationFn<any, any> = (
320
- columnId,
321
- _leafRows,
322
- childRows,
323
- ) => {
324
- return childRows.reduce((acc, next) => {
325
- const v = next.getValue(columnId)
326
- return acc + (typeof v === 'number' ? v : 0)
327
- }, 0)
328
- }
329
- ```
58
+ Correct: `tableFeatures({ columnGroupingFeature, groupedRowModel: createGroupedRowModel() })`
330
59
 
331
- Built-in `mean`, `median`, `unique`, `uniqueCount`, `count` use `leafRows`. `sum`, `min`, `max`, `extent` use `childRows`.
60
+ The grouped slot and aggregation registry require `columnGroupingFeature`.
332
61
 
333
- Source: packages/table-core/src/fns/aggregationFns.ts
62
+ Source: `packages/table-core/src/types/TableFeatures.ts#FeatureSlotPrereqs`
334
63
 
335
- ### [MEDIUM] Expecting grouped columns to keep their original position
64
+ ### [HIGH] Treating rendered rows as underlying records
336
65
 
337
- Wrong:
338
-
339
- ```ts
340
- const table = useTable({
341
- features,
342
- columns,
343
- data,
344
- initialState: {
345
- columnOrder: ['firstName', 'lastName', 'age', 'status'], // explicit
346
- grouping: ['status'],
347
- },
348
- // status jumps to position 0 — columnOrder is "overridden"
349
- })
350
- ```
66
+ Wrong: `const leafCount = table.getRowModel().flatRows.filter(row => !row.subRows.length).length`
351
67
 
352
68
  Correct:
353
69
 
354
70
  ```ts
355
- const table = useTable({
356
- features,
357
- columns,
358
- data,
359
- initialState: {
360
- columnOrder: ['firstName', 'lastName', 'age', 'status'],
361
- grouping: ['status'],
362
- },
363
- groupedColumnMode: false, // keep columnOrder intact
364
- })
365
-
366
- // Or hide grouped columns entirely:
367
- // groupedColumnMode: 'remove'
71
+ const countLeafRows = (rows: typeof groupRow.subRows): number =>
72
+ rows.reduce(
73
+ (count, row) =>
74
+ count + (row.subRows.length ? countLeafRows(row.subRows) : 1),
75
+ 0,
76
+ )
77
+ const leafCount = countLeafRows(groupRow.subRows)
368
78
  ```
369
79
 
370
- `columnGroupingFeature.getDefaultTableOptions` sets `groupedColumnMode: 'reorder'`, which moves grouped columns to the start.
371
-
372
- Source: packages/table-core/src/features/column-ordering/columnOrderingFeature.utils.ts
373
-
374
- ### [LOW] Calling `getSelectedRowModel()` on a grouped table expecting grouped rows
80
+ Count descendants from one group row rather than the flattened render model,
81
+ where group rows and expanded rows may both appear. The current
82
+ `table.getRowModel().rows` is render order, while original dataset counts come
83
+ from the data owner.
375
84
 
376
- Wrong:
85
+ Source: `docs/framework/react/guide/grouping.md`
377
86
 
378
- ```ts
379
- // returns selection from the CORE model, not the grouped projection
380
- const selectedRows = table.getSelectedRowModel().rows
381
- // Doesn't reflect grouping — leaf rows only
382
- ```
383
-
384
- Correct:
385
-
386
- ```ts
387
- table.getSelectedRowModel() // selection from raw data
388
- table.getFilteredSelectedRowModel() // selection within current filters
389
- table.getGroupedSelectedRowModel() // selection within current groups
390
- ```
87
+ ### [HIGH] Rendering every cell identically
391
88
 
392
- Three distinct APIs. Pick the model matching the question being asked.
89
+ Wrong: `render(cell.getValue())`
393
90
 
394
- Source: packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts
91
+ Correct: `render(cell.getIsPlaceholder() ? null : cell.getValue())`
395
92
 
396
- ### [CRITICAL] Reimplementing aggregation manually
397
-
398
- Wrong:
399
-
400
- ```ts
401
- // Hand-rolled groupBy + reduce, bypassing the table
402
- const grouped = useMemo(() => {
403
- const map = new Map<string, Person[]>()
404
- data.forEach((row) => {
405
- const key = row.status
406
- if (!map.has(key)) map.set(key, [])
407
- map.get(key)!.push(row)
408
- })
409
- return Array.from(map.entries()).map(([k, rows]) => ({
410
- status: k,
411
- avgAge: rows.reduce((s, r) => s + r.age, 0) / rows.length,
412
- }))
413
- }, [data])
414
- ```
415
-
416
- Correct:
417
-
418
- ```ts
419
- const features = tableFeatures({
420
- columnGroupingFeature,
421
- rowExpandingFeature,
422
- groupedRowModel: createGroupedRowModel(),
423
- expandedRowModel: createExpandedRowModel(),
424
- aggregationFns,
425
- })
426
- const table = useTable({
427
- features,
428
- columns: columnHelper.columns([
429
- columnHelper.accessor('status', { enableGrouping: true }),
430
- columnHelper.accessor('age', { aggregationFn: 'mean' }),
431
- ]),
432
- data,
433
- })
434
- table.setGrouping(['status'])
435
- ```
93
+ Placeholder and aggregated cells do not represent ordinary leaf values.
436
94
 
437
- Source: maintainer interview (Phase 4, 2026-05-17)
95
+ Source: `examples/react/grouping/src/main.tsx`
438
96
 
439
- ## See also
97
+ ## API Discovery
440
98
 
441
- - `tanstack-table/row-expanding` required pairing for grouped drill-down
442
- - `tanstack-table/customizing-feature-behavior` — `aggregationFn` authoring
443
- - `tanstack-table/row-selection` — `getGroupedSelectedRowModel` distinction
99
+ Inspect `node_modules/@tanstack/table-core/src/features/column-grouping/` and `src/fns/aggregationFns.ts`.