@tanstack/angular-table 9.0.0-alpha.9 → 9.0.0-beta.10

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 (54) hide show
  1. package/README.md +127 -0
  2. package/dist/README.md +127 -0
  3. package/dist/fesm2022/tanstack-angular-table-static-functions.mjs +6 -0
  4. package/dist/fesm2022/tanstack-angular-table-static-functions.mjs.map +1 -0
  5. package/dist/fesm2022/tanstack-angular-table.mjs +1299 -248
  6. package/dist/fesm2022/tanstack-angular-table.mjs.map +1 -1
  7. package/dist/types/tanstack-angular-table-static-functions.d.ts +1 -0
  8. package/dist/types/tanstack-angular-table.d.ts +787 -0
  9. package/package.json +39 -19
  10. package/skills/angular/angular-rendering-directives/SKILL.md +415 -0
  11. package/skills/angular/angular-rendering-directives/references/content-shapes.md +142 -0
  12. package/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md +89 -0
  13. package/skills/angular/angular-rendering-directives/references/di-tokens.md +171 -0
  14. package/skills/angular/angular-rendering-directives/references/flex-render-component-options.md +64 -0
  15. package/skills/angular/client-to-server/SKILL.md +468 -0
  16. package/skills/angular/compose-with-tanstack-query/SKILL.md +486 -0
  17. package/skills/angular/compose-with-tanstack-store/SKILL.md +405 -0
  18. package/skills/angular/compose-with-tanstack-virtual/SKILL.md +399 -0
  19. package/skills/angular/getting-started/SKILL.md +487 -0
  20. package/skills/angular/getting-started/references/feature-row-model-mapping.md +51 -0
  21. package/skills/angular/migrate-v8-to-v9/SKILL.md +422 -0
  22. package/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md +268 -0
  23. package/skills/angular/production-readiness/SKILL.md +472 -0
  24. package/skills/angular/table-state/SKILL.md +422 -0
  25. package/skills/angular/table-state/references/external-atoms-and-app-hook.md +153 -0
  26. package/src/flex-render/context.ts +14 -0
  27. package/src/flex-render/flags.ts +34 -0
  28. package/src/flex-render/flexRenderComponent.ts +288 -0
  29. package/src/flex-render/flexRenderComponentFactory.ts +251 -0
  30. package/src/flex-render/renderer.ts +393 -0
  31. package/src/flex-render/view.ts +226 -0
  32. package/src/flexRender.ts +124 -0
  33. package/src/helpers/cell.ts +108 -0
  34. package/src/helpers/createTableHook.ts +498 -0
  35. package/src/helpers/flexRenderCell.ts +136 -0
  36. package/src/helpers/header.ts +101 -0
  37. package/src/helpers/table.ts +87 -0
  38. package/src/index.ts +23 -70
  39. package/src/injectTable.ts +146 -0
  40. package/src/{lazy-signal-initializer.ts → lazySignalInitializer.ts} +2 -2
  41. package/src/reactivity.ts +105 -0
  42. package/static-functions/index.ts +1 -0
  43. package/static-functions/ng-package.json +6 -0
  44. package/dist/esm2022/flex-render.mjs +0 -148
  45. package/dist/esm2022/index.mjs +0 -48
  46. package/dist/esm2022/lazy-signal-initializer.mjs +0 -43
  47. package/dist/esm2022/proxy.mjs +0 -83
  48. package/dist/esm2022/tanstack-angular-table.mjs +0 -5
  49. package/dist/flex-render.d.ts +0 -30
  50. package/dist/index.d.ts +0 -5
  51. package/dist/lazy-signal-initializer.d.ts +0 -5
  52. package/dist/proxy.d.ts +0 -3
  53. package/src/flex-render.ts +0 -184
  54. package/src/proxy.ts +0 -97
@@ -0,0 +1,422 @@
1
+ ---
2
+ name: angular/migrate-v8-to-v9
3
+ description: >
4
+ Mechanical v8 → v9 migration for `@tanstack/angular-table`: `createAngularTable` →
5
+ `injectTable`, `get*RowModel()` options → row-model factories on the `features` object (no
6
+ separate `rowModels` option; fn registries like `filterFns`/`sortFns` are also slots on
7
+ `features`), required `features` via `tableFeatures()`, state access via
8
+ `table.atoms.<slice>.get()` or `table.state` instead of `table.getState()`,
9
+ `createColumnHelper<TFeatures, TData>()` generic-order flip, every type now requires `TFeatures`,
10
+ `enablePinning` split into `enableColumnPinning` / `enableRowPinning`, `sortingFn` → `sortFn`
11
+ rename pile, `ColumnSizingInfo` → `ColumnResizing` split, removal of `_`-prefixed internals,
12
+ signal-backed atoms replacing v8 memoized accessors, and structural-directive rendering replacing
13
+ v8 component-based rendering.
14
+ type: lifecycle
15
+ library: tanstack-table
16
+ framework: angular
17
+ library_version: '9.0.0-alpha.48'
18
+ requires:
19
+ - angular/table-state
20
+ - angular/getting-started
21
+ - angular/angular-rendering-directives
22
+ sources:
23
+ - TanStack/table:docs/framework/angular/guide/migrating.md
24
+ - TanStack/table:docs/framework/angular/angular-table.md
25
+ - TanStack/table:packages/angular-table/src/injectTable.ts
26
+ - TanStack/table:packages/angular-table/src/reactivity.ts
27
+ ---
28
+
29
+ # Migrate from TanStack Table v8 to v9 (Angular)
30
+
31
+ > **Angular does not ship a legacy v8 API in v9** (unlike React's
32
+ > `useLegacyTable`). You migrate directly to v9's `injectTable` + `features`
33
+ > shape (row-model factories and fn registries now live on the `features` object).
34
+ > There is no incremental in-place adapter — the public entrypoint name itself changes.
35
+
36
+ This skill is a mechanical translation table. Work through it top-to-bottom.
37
+
38
+ For exhaustive lookup tables (row-model mapping, feature registration, type
39
+ generics, sorting renames, sizing-vs-resizing split, etc.) →
40
+ [`references/v8-to-v9-mapping.md`](references/v8-to-v9-mapping.md).
41
+
42
+ ---
43
+
44
+ ## 1. Entrypoint rename
45
+
46
+ ```ts
47
+ // v8
48
+ import { createAngularTable, getCoreRowModel } from '@tanstack/angular-table'
49
+
50
+ const v8Table = createAngularTable(() => ({
51
+ columns,
52
+ data: data(),
53
+ getCoreRowModel: getCoreRowModel(),
54
+ }))
55
+
56
+ // v9
57
+ import { injectTable, tableFeatures } from '@tanstack/angular-table'
58
+
59
+ const features = tableFeatures({}) // empty is valid; core row model is automatic
60
+
61
+ const v9Table = injectTable(() => ({
62
+ features,
63
+ columns,
64
+ data: data(),
65
+ }))
66
+ ```
67
+
68
+ Key behavioral change: **the `injectTable` initializer re-runs when signals
69
+ inside it change**, then the adapter calls `table.setOptions({ ...prev, ...new })`.
70
+ Move stable values (`columns`, `features`) **outside** the initializer so they
71
+ aren't recreated on every data update.
72
+
73
+ ---
74
+
75
+ ## 2. Required new option: `features`
76
+
77
+ v9 is opt-in for every feature. `features` is required. Row-model factories and
78
+ fn registries are now **slots on the features object** — there is no separate
79
+ `rowModels` option.
80
+
81
+ ```ts
82
+ // v8 — features were bundled, row models added piecewise
83
+ createAngularTable(() => ({
84
+ columns,
85
+ data: data(),
86
+ getCoreRowModel: getCoreRowModel(),
87
+ getFilteredRowModel: getFilteredRowModel(),
88
+ getSortedRowModel: getSortedRowModel(),
89
+ getPaginationRowModel: getPaginationRowModel(),
90
+ filterFns, // root option
91
+ sortingFns, // root option
92
+ }))
93
+
94
+ // v9
95
+ import {
96
+ injectTable,
97
+ tableFeatures,
98
+ columnFilteringFeature,
99
+ rowSortingFeature,
100
+ rowPaginationFeature,
101
+ createFilteredRowModel,
102
+ createSortedRowModel,
103
+ createPaginatedRowModel,
104
+ filterFns,
105
+ sortFns, // note rename: sortingFns → sortFns
106
+ } from '@tanstack/angular-table'
107
+
108
+ const features = tableFeatures({
109
+ columnFilteringFeature,
110
+ rowSortingFeature,
111
+ rowPaginationFeature,
112
+ filteredRowModel: createFilteredRowModel(), // factory is now a features slot
113
+ sortedRowModel: createSortedRowModel(),
114
+ paginatedRowModel: createPaginatedRowModel(),
115
+ filterFns, // fn registry is also a features slot
116
+ sortFns, // note rename: sortingFns → sortFns
117
+ })
118
+
119
+ injectTable(() => ({
120
+ features,
121
+ columns,
122
+ data: data(),
123
+ }))
124
+ ```
125
+
126
+ Row-model and feature lookup tables → [`references/v8-to-v9-mapping.md`](references/v8-to-v9-mapping.md#row-model-migration-table).
127
+
128
+ ---
129
+
130
+ ## 3. State access: `getState()` → atoms or `table.state`
131
+
132
+ ```ts
133
+ // v8
134
+ const { sorting, pagination } = table.getState()
135
+
136
+ // v9 — full-state flat proxy
137
+ const { sorting, pagination } = table.state
138
+
139
+ // v9 — per slice (preferred for Angular render code)
140
+ const sorting = table.atoms.sorting.get()
141
+ const pagination = table.atoms.pagination.get()
142
+ ```
143
+
144
+ In Angular, all three (`table.atoms.<slice>`, `table.state`,
145
+ `table.baseAtoms.<slice>`) are signal-backed — reading them inside a template,
146
+ `computed(...)`, or `effect(...)` registers an Angular dependency
147
+ automatically. No `toSignal(...)` wrappers needed. Prefer direct atom reads for
148
+ specific slices; keep `table.state` for full-state JSON/debug output or code
149
+ that genuinely wants the flat state shape.
150
+
151
+ See `tanstack-table/angular/table-state` for the full state surface mental
152
+ model.
153
+
154
+ ---
155
+
156
+ ## 4. Controlled state — `on[State]Change` shape
157
+
158
+ The shape is largely the same. **`onStateChange` (the single global v8 hook) is
159
+ gone in v9.** Slices are controlled individually via `state.<slice>` +
160
+ `on[State]Change` callbacks. Each callback receives either a new value or an
161
+ updater function:
162
+
163
+ ```ts
164
+ // v9 pattern
165
+ import { signal } from '@angular/core'
166
+ import type { SortingState, PaginationState } from '@tanstack/angular-table'
167
+
168
+ readonly sorting = signal<SortingState>([])
169
+ readonly pagination = signal<PaginationState>({ pageIndex: 0, pageSize: 10 })
170
+
171
+ readonly table = injectTable(() => ({
172
+ features,
173
+ columns,
174
+ data: this.data(),
175
+ state: {
176
+ sorting: this.sorting(),
177
+ pagination: this.pagination(),
178
+ },
179
+ onSortingChange: (updater) => {
180
+ updater instanceof Function
181
+ ? this.sorting.update(updater)
182
+ : this.sorting.set(updater)
183
+ },
184
+ onPaginationChange: (updater) => {
185
+ updater instanceof Function
186
+ ? this.pagination.update(updater)
187
+ : this.pagination.set(updater)
188
+ },
189
+ }))
190
+ ```
191
+
192
+ > Always check `updater instanceof Function` (or `typeof updater === 'function'`).
193
+ > TanStack Table calls the callback with both shapes depending on the
194
+ > transition.
195
+
196
+ ---
197
+
198
+ ## 5. Column helper generic-order flip
199
+
200
+ ```ts
201
+ // v8
202
+ const columnHelper = createColumnHelper<Person>()
203
+
204
+ // v9 — TFeatures FIRST, then TData
205
+ const columnHelper = createColumnHelper<typeof features, Person>()
206
+ ```
207
+
208
+ New in v9: `columnHelper.columns([...])` preserves each column's `TValue` —
209
+ prefer it over a bare array literal:
210
+
211
+ ```ts
212
+ const columns = columnHelper.columns([
213
+ columnHelper.accessor('firstName', {
214
+ header: 'First',
215
+ cell: (i) => i.getValue(),
216
+ }),
217
+ columnHelper.display({
218
+ id: 'actions',
219
+ header: 'Actions',
220
+ cell: () => 'Edit',
221
+ }),
222
+ ])
223
+ ```
224
+
225
+ If you don't want to repeat `TFeatures` everywhere, use `createTableHook(...)`
226
+ and the resulting `createAppColumnHelper<Person>()` which pre-binds features.
227
+
228
+ Every public type now requires `TFeatures` (`ColumnDef<TFeatures, TData, TValue>`,
229
+ `Cell<TFeatures, TData, TValue>`, etc.). Full mapping →
230
+ [`references/v8-to-v9-mapping.md`](references/v8-to-v9-mapping.md#type-generics--every-type-takes-tfeatures-now).
231
+
232
+ ---
233
+
234
+ ## 6. Rendering — directive-based, with shorthand directives
235
+
236
+ v8 Angular rendering was already directive-flavored, but v9 adds the
237
+ **shorthand directives** (`*flexRenderCell`, `*flexRenderHeader`,
238
+ `*flexRenderFooter`) that auto-resolve the column-def slot and context. Prefer
239
+ them over the long `*flexRender="… ; props: …"` form.
240
+
241
+ ```html
242
+ <!-- v8 / v9 long form (still works) -->
243
+ <td
244
+ *flexRender="cell.column.columnDef.cell; props: cell.getContext(); let rendered"
245
+ >
246
+ {{ rendered }}
247
+ </td>
248
+
249
+ <!-- v9 shorthand — recommended -->
250
+ <td *flexRenderCell="cell; let value">{{ value }}</td>
251
+ <th *flexRenderHeader="header; let value">{{ value }}</th>
252
+ <th *flexRenderFooter="footer; let value">{{ value }}</th>
253
+ ```
254
+
255
+ ```ts
256
+ import { FlexRender } from '@tanstack/angular-table' // ← imports both directives
257
+ @Component({ imports: [FlexRender], ... })
258
+ ```
259
+
260
+ v9-only:
261
+
262
+ - `flexRenderComponent(Component, { inputs, outputs, bindings, directives, injector })`
263
+ for explicit component rendering.
264
+ - DI tokens (`TanStackTable` / `TanStackTableHeader` / `TanStackTableCell`
265
+ directives + `injectTableContext()` / `injectTableHeaderContext()` /
266
+ `injectTableCellContext()` / `injectFlexRenderContext()`) — no more input
267
+ drilling.
268
+ - Column-def `cell` / `header` / `footer` functions run inside
269
+ `runInInjectionContext`, so `inject(...)` and signals work in them.
270
+
271
+ See `tanstack-table/angular/angular-rendering-directives` for the full surface.
272
+
273
+ ---
274
+
275
+ ## 7. Reactivity model — signals replace v8 memo accessors
276
+
277
+ v8 backed reactivity with manual memoized getters. v9's adapter
278
+ (`angularReactivity(injector)`) backs every readonly atom with an Angular
279
+ `computed` and every writable atom with an Angular `signal`. Consequences:
280
+
281
+ - **No `toSignal(...)` adapters around table state.** Read `table.atoms.x.get()`
282
+ directly inside templates, `computed`, `effect` for specific slices. Use
283
+ `table.state` when you need the full-state flat shape.
284
+ - **`computed(...)` is for derivation / equality, not for "make it reactive".**
285
+ Use `{ equal: shallow }` from `@tanstack/angular-table` on object/array
286
+ slices to skip downstream work on no-op updates.
287
+ - **The `injectTable` initializer re-runs on signal changes.** Don't put
288
+ expensive object literals in there.
289
+
290
+ ---
291
+
292
+ ## 8. Renames at a glance
293
+
294
+ - `sortingFn` → `sortFn`, `sortingFns` → `sortFns`, `SortingFn` → `SortFn`
295
+ (full table in [`references/v8-to-v9-mapping.md`](references/v8-to-v9-mapping.md#naming-renames--sorting)).
296
+ - `enablePinning` → `enableColumnPinning` / `enableRowPinning` (split).
297
+ - `columnSizingInfo` state → `columnResizing` state (sizing/resizing split into
298
+ two features — see [`references/v8-to-v9-mapping.md`](references/v8-to-v9-mapping.md#column-sizing-vs-resizing--split)).
299
+ - All `_`-prefixed internal APIs removed; use the public equivalents.
300
+
301
+ ---
302
+
303
+ ## Migration checklist
304
+
305
+ - [ ] Replace `createAngularTable` import + call with `injectTable`.
306
+ - [ ] Add `features: tableFeatures({...})` (or `stockFeatures`) — required.
307
+ - [ ] Convert every `get*RowModel()` option to a slot on the `features` object
308
+ using the matching `create*RowModel()` factory.
309
+ - [ ] Move `filterFns` / `sortFns` / `aggregationFns` fn registries to slots
310
+ on the `features` object (not as factory parameters).
311
+ - [ ] Update `createColumnHelper<Person>()` → `createColumnHelper<typeof features, Person>()`.
312
+ - [ ] Update every `ColumnDef<Person>` / `Cell<Person, X>` etc. to include
313
+ `TFeatures`.
314
+ - [ ] Replace `table.getState().slice` reads with `table.atoms.<slice>.get()`
315
+ where possible; use `table.state` for full-state/debug reads.
316
+ - [ ] Remove any usage of the v8 single `onStateChange` — split into per-slice
317
+ `on[State]Change`.
318
+ - [ ] In `on[State]Change` callbacks, handle both value and updater-fn shapes.
319
+ - [ ] Move `columns` and `features` **outside** the `injectTable` initializer.
320
+ - [ ] Switch any `flexRender` long-form to `*flexRenderCell` / `*flexRenderHeader` /
321
+ `*flexRenderFooter` shorthand where applicable.
322
+ - [ ] Where you need component rendering with explicit options, switch wrapper
323
+ shape to `flexRenderComponent(Component, { inputs, outputs, ... })`.
324
+ - [ ] Replace prop-drilled cell/header inputs with
325
+ `injectTableCellContext()` / `injectTableHeaderContext()` /
326
+ `injectFlexRenderContext()` (optional but worthwhile).
327
+ - [ ] Rename `sortingFn` → `sortFn`, `getSortingFn` → `getSortFn`,
328
+ `sortingFns` → `sortFns`, `SortingFn` → `SortFn`.
329
+ - [ ] Replace `columnSizingInfo` state / setters / change handler with the
330
+ `columnResizing` equivalents; add `columnSizingFeature` and
331
+ `columnResizingFeature` to `features` if you actually drag-resize
332
+ (`columnResizingFeature` requires `columnSizingFeature`).
333
+ - [ ] Replace `enablePinning` with `enableColumnPinning` / `enableRowPinning`.
334
+ - [ ] Update `ColumnMeta` module augmentation to include the `TFeatures`
335
+ generic.
336
+ - [ ] Drop any `_`-prefixed internal API usages; replace with public
337
+ equivalents.
338
+ - [ ] (Optional) Adopt `tableOptions(...)` for shared base config.
339
+ - [ ] (Optional) Adopt `createTableHook(...)` for app-wide table infrastructure.
340
+
341
+ ---
342
+
343
+ ## Failure modes
344
+
345
+ ### 1. (CRITICAL) Leaving `getCoreRowModel()` / `getSortedRowModel()` / etc. in v9 options
346
+
347
+ These options don't exist anymore. The equivalent factories become slots on the
348
+ `features` object (e.g. `sortedRowModel: createSortedRowModel()`). The TypeScript
349
+ error is loud but agents sometimes silence it with `as any` — don't.
350
+
351
+ ### 2. (CRITICAL) Reaching for `createAngularTable` from v8 muscle memory
352
+
353
+ Always `injectTable(() => ({...}))`. The injection-context requirement means
354
+ it must run from a class field, constructor, or
355
+ `runInInjectionContext(injector, () => injectTable(...))`.
356
+
357
+ ### 3. (CRITICAL) Registering a feature but forgetting its row model
358
+
359
+ ```ts
360
+ // ❌ filtering enabled, but no filtered row model — UI changes, rows don't filter
361
+ const features = tableFeatures({ columnFilteringFeature }) // missing filteredRowModel
362
+
363
+ // ✅
364
+ const features = tableFeatures({
365
+ columnFilteringFeature,
366
+ filteredRowModel: createFilteredRowModel(),
367
+ filterFns,
368
+ })
369
+ ```
370
+
371
+ Same for sorting, pagination, expanding, grouping, faceting. Selection,
372
+ visibility, ordering, pinning, sizing, resizing do **not** need a row model.
373
+
374
+ ### 4. (HIGH) `getState()` → `table.state` text replacement can be too broad
375
+
376
+ Bulk-replacing `table.getState().x` with `table.state.x` works for _current
377
+ value_ reads, but it hides which slice the component depends on. For Angular
378
+ render code and reactive derivations, switch to `table.atoms.x.get()` — it's
379
+ already signal-backed and needs no wrapper. Keep `table.state` for full-state
380
+ debug output.
381
+
382
+ ### 5. (HIGH) Stale `sortingFn` / `sortingFns` references in column defs
383
+
384
+ The rename is mechanical: `sortingFn` → `sortFn`, `sortingFns` → `sortFns`,
385
+ `getSortingFn` → `getSortFn`. Missed renames produce silent runtime fallbacks
386
+ to default sort.
387
+
388
+ ### 6. (HIGH) Column helper using v8 generic order
389
+
390
+ ```ts
391
+ // ❌ TS will complain — the first generic is TFeatures, not TData
392
+ const columnHelper = createColumnHelper<Person>()
393
+ ```
394
+
395
+ ### 7. (HIGH) Putting `features` / `columns` inside the `injectTable` initializer
396
+
397
+ The v8 mental model was "build columns inside the hook". v9's
398
+ `injectTable` initializer re-runs on every signal read change — keep heavy
399
+ literals outside. Because row-model factories and fn registries live on the
400
+ `features` object, keeping `features` stable at module scope covers all of them.
401
+
402
+ Lower-severity failure modes (MEDIUM/LOW: `stockFeatures` cleanup, `enablePinning`
403
+ removal, `columnSizingInfo` rename, single-handler porting, hand-rolled
404
+ `TFeatures` in render fns, `_`-prefix internal usage, reimplementing built-in
405
+ APIs, `ColumnMeta` augmentation drift, `flexRender` as a function, mixing v8/v9
406
+ atoms) → [`references/v8-to-v9-mapping.md`](references/v8-to-v9-mapping.md#lower-severity-failure-modes-mediumlow).
407
+
408
+ ---
409
+
410
+ ## References
411
+
412
+ - [Full v8 → v9 mapping tables (row models, features, types, renames, MEDIUM failure modes)](references/v8-to-v9-mapping.md)
413
+
414
+ ---
415
+
416
+ ## See also
417
+
418
+ - `tanstack-table/angular/getting-started` — what the v9 target shape looks like
419
+ - `tanstack-table/angular/table-state` — signal-backed atom model
420
+ - `tanstack-table/angular/angular-rendering-directives` — full rendering API
421
+ - `tanstack-table/angular/production-readiness` — once compiling, optimize the bundle
422
+ - `tanstack-table/core/migrate-v8-to-v9` — framework-agnostic core changes
@@ -0,0 +1,268 @@
1
+ # v8 → v9 Mapping Tables — Full Reference
2
+
3
+ Mechanical translation tables and detailed renames for the Angular Table v8 →
4
+ v9 migration. The SKILL.md keeps the primary patterns; this file is the
5
+ exhaustive lookup.
6
+
7
+ ---
8
+
9
+ ## Row-model migration table
10
+
11
+ Row-model factories and fn registries are now **slots on the `features` object**,
12
+ not a separate `rowModels` option. Factory calls no longer take fn arguments;
13
+ pass the fn map as a sibling slot instead.
14
+
15
+ | v8 option | v9 `features` slot key | v9 factory call | v9 fn registry slot |
16
+ | -------------------------- | ---------------------- | ----------------------------- | ------------------- |
17
+ | `getCoreRowModel()` | (automatic) | — | — |
18
+ | `getFilteredRowModel()` | `filteredRowModel` | `createFilteredRowModel()` | `filterFns` |
19
+ | `getSortedRowModel()` | `sortedRowModel` | `createSortedRowModel()` | `sortFns` |
20
+ | `getPaginationRowModel()` | `paginatedRowModel` | `createPaginatedRowModel()` | — |
21
+ | `getExpandedRowModel()` | `expandedRowModel` | `createExpandedRowModel()` | — |
22
+ | `getGroupedRowModel()` | `groupedRowModel` | `createGroupedRowModel()` | `aggregationFns` |
23
+ | `getFacetedRowModel()` | `facetedRowModel` | `createFacetedRowModel()` | — |
24
+ | `getFacetedMinMaxValues()` | `facetedMinMaxValues` | `createFacetedMinMaxValues()` | — |
25
+ | `getFacetedUniqueValues()` | `facetedUniqueValues` | `createFacetedUniqueValues()` | — |
26
+
27
+ ## Feature registration table
28
+
29
+ | v8 (implicit) | v9 feature import |
30
+ | --------------- | ------------------------- |
31
+ | filter columns | `columnFilteringFeature` |
32
+ | global filter | `globalFilteringFeature` |
33
+ | sort rows | `rowSortingFeature` |
34
+ | pagination | `rowPaginationFeature` |
35
+ | row selection | `rowSelectionFeature` |
36
+ | expanding rows | `rowExpandingFeature` |
37
+ | pin rows | `rowPinningFeature` |
38
+ | pin columns | `columnPinningFeature` |
39
+ | hide columns | `columnVisibilityFeature` |
40
+ | reorder columns | `columnOrderingFeature` |
41
+ | size columns | `columnSizingFeature` |
42
+ | resize columns | `columnResizingFeature` |
43
+ | group columns | `columnGroupingFeature` |
44
+ | facet columns | `columnFacetingFeature` |
45
+
46
+ > If you don't want to think about tree-shaking yet, you can pass
47
+ > `stockFeatures`:
48
+ >
49
+ > ```ts
50
+ > import { stockFeatures } from '@tanstack/angular-table'
51
+ > features: stockFeatures
52
+ > ```
53
+ >
54
+ > This restores v8-like "everything bundled" behavior — but the v9 bundle
55
+ > wins are gone. Plan to migrate to a curated `tableFeatures({...})` as part of
56
+ > productionization.
57
+
58
+ ---
59
+
60
+ ## Type generics — every type takes `TFeatures` now
61
+
62
+ ```txt
63
+ v8 v9
64
+ --- ---
65
+ Column<TData> → Column<TFeatures, TData, TValue>
66
+ ColumnDef<TData> → ColumnDef<TFeatures, TData, TValue>
67
+ Table<TData> → Table<TFeatures, TData>
68
+ Row<TData> → Row<TFeatures, TData>
69
+ Cell<TData, TValue> → Cell<TFeatures, TData, TValue>
70
+ Header<TData, TValue> → Header<TFeatures, TData, TValue>
71
+ HeaderContext<TData, TValue> → HeaderContext<TFeatures, TData, TValue>
72
+ CellContext<TData, TValue> → CellContext<TFeatures, TData, TValue>
73
+ ```
74
+
75
+ Easiest fix: extract `typeof features` once.
76
+
77
+ ```ts
78
+ const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
79
+
80
+ type Features = typeof features
81
+
82
+ const columns: Array<ColumnDef<Features, Person>> = [
83
+ /* … */
84
+ ]
85
+ ```
86
+
87
+ If you're on `stockFeatures`:
88
+
89
+ ```ts
90
+ import type { StockFeatures, ColumnDef } from '@tanstack/angular-table'
91
+ const columns: Array<ColumnDef<StockFeatures, Person>> = [
92
+ /* … */
93
+ ]
94
+ ```
95
+
96
+ `ColumnMeta` module augmentation also needs `TFeatures`:
97
+
98
+ ```ts
99
+ declare module '@tanstack/angular-table' {
100
+ interface ColumnMeta<
101
+ TFeatures extends TableFeatures,
102
+ TData extends RowData,
103
+ TValue,
104
+ > {
105
+ align?: 'left' | 'right'
106
+ }
107
+ }
108
+ ```
109
+
110
+ ---
111
+
112
+ ## Naming renames — sorting
113
+
114
+ | v8 | v9 |
115
+ | ----------------------------------- | ------------------------ |
116
+ | `sortingFn` (column-def field) | `sortFn` |
117
+ | `column.getSortingFn()` | `column.getSortFn()` |
118
+ | `column.getAutoSortingFn()` | `column.getAutoSortFn()` |
119
+ | `SortingFn` type | `SortFn` |
120
+ | `SortingFns` interface | `SortFns` |
121
+ | `sortingFns` (built-in fn registry) | `sortFns` |
122
+
123
+ Find-and-replace, then verify `sortFns` is a slot on `features` alongside `sortedRowModel: createSortedRowModel()`.
124
+
125
+ ---
126
+
127
+ ## Column sizing vs resizing — split
128
+
129
+ v8 combined sizing and resizing into one feature. v9 splits them so you can
130
+ ship only what you use.
131
+
132
+ | v8 | v9 |
133
+ | --------------------------------- | ---------------------------------------------------------- |
134
+ | `ColumnSizing` (single feature) | `columnSizingFeature` + `columnResizingFeature` (separate) |
135
+ | `columnSizingInfo` state | `columnResizing` state |
136
+ | `setColumnSizingInfo()` | `setColumnResizing()` |
137
+ | `onColumnSizingInfoChange` option | `onColumnResizingChange` option |
138
+
139
+ If you only render fixed-width columns and never drag-to-resize, import only
140
+ `columnSizingFeature`.
141
+
142
+ ---
143
+
144
+ ## Pinning option split
145
+
146
+ ```ts
147
+ // v8
148
+ enablePinning: true
149
+
150
+ // v9 — explicit
151
+ enableColumnPinning: true
152
+ enableRowPinning: true
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Row API: privates promoted to public
158
+
159
+ | v8 | v9 |
160
+ | ---------------------------------------- | -------------------------------------- |
161
+ | `row._getAllCellsByColumnId()` (private) | `row.getAllCellsByColumnId()` (public) |
162
+
163
+ All other `_`-prefixed internal APIs from v8 are removed in v9 — use the
164
+ public equivalents. If you were touching `_`-prefixed members, you were on
165
+ unsupported territory; v9 forces the fix.
166
+
167
+ ---
168
+
169
+ ## `tableOptions(...)` — new composition helper
170
+
171
+ v9 ships `tableOptions(...)` for type-safe partial option composition. Useful
172
+ during migration if you have shared base config:
173
+
174
+ ```ts
175
+ import { tableOptions, tableFeatures, rowSortingFeature } from '@tanstack/angular-table'
176
+
177
+ const baseOptions = tableOptions({
178
+ features: tableFeatures({
179
+ rowSortingFeature,
180
+ sortedRowModel: createSortedRowModel(),
181
+ sortFns,
182
+ }),
183
+ debugTable: isDevMode(),
184
+ })
185
+
186
+ readonly table = injectTable(() => ({
187
+ ...baseOptions,
188
+ columns: this.columns,
189
+ data: this.data(),
190
+ }))
191
+ ```
192
+
193
+ And for whole-app patterns, `createTableHook(...)` — see
194
+ `tanstack-table/angular/angular-rendering-directives`.
195
+
196
+ ---
197
+
198
+ ## `RowData` type tightened
199
+
200
+ `RowData` is now stricter (object-like; no primitives). If you had
201
+ `type Row = string`, that won't fly in v9 — wrap it in an object.
202
+
203
+ ---
204
+
205
+ ## Lower-severity failure modes (MEDIUM/LOW)
206
+
207
+ ### Skipping `stockFeatures` cleanup later
208
+
209
+ Using `stockFeatures` is a fine migration shortcut, but it forgoes the v9
210
+ bundle wins. Once everything compiles, swap `stockFeatures` for an explicit
211
+ `tableFeatures({...})` listing only the features you use.
212
+
213
+ ### Forgetting `enablePinning` is gone
214
+
215
+ `enablePinning: true` silently does nothing. Use `enableColumnPinning: true`
216
+ and/or `enableRowPinning: true`.
217
+
218
+ ### Forgetting `columnSizingInfo` is gone
219
+
220
+ Replace state name `columnSizingInfo` with `columnResizing`, setter
221
+ `setColumnSizingInfo` with `setColumnResizing`, handler
222
+ `onColumnSizingInfoChange` with `onColumnResizingChange`. And add
223
+ `columnResizingFeature` to `features` if you actually need resizing.
224
+
225
+ ### Single global `onStateChange` ported as a giant per-slice fan-out
226
+
227
+ In v9 each slice has its own callback. If you previously used `onStateChange`
228
+ to multiplex changes, port to the specific `on[State]Change` callbacks you
229
+ actually care about — don't recreate a megaswitch.
230
+
231
+ ### Hand-rolling `TFeatures` in render-fn types
232
+
233
+ When a `cell` / `header` function signature requires `CellContext<TFeatures, TData, TValue>`,
234
+ let `createColumnHelper<typeof features, TData>()` infer it for you. Spelling
235
+ features by hand in dozens of render-fn signatures is a sign you should be
236
+ using `createAppColumnHelper` from `createTableHook`.
237
+
238
+ ### Reaching for `_`-prefixed internals because the public method "doesn't exist"
239
+
240
+ The "missing" method usually means the feature isn't in `features`. Add the
241
+ feature; don't peek at internals.
242
+
243
+ ### Reimplementing what the table API already does
244
+
245
+ Symptoms of v8 muscle memory carrying through:
246
+
247
+ - Manually sorting the data signal in `effect(...)` instead of
248
+ `table.setSorting(...)` and using `table.getRowModel().rows`.
249
+ - Manually paginating the rows array instead of using `paginatedRowModel`.
250
+ - Hand-rolling `getSelectedRowModel().flatRows` from a `rowSelection` signal.
251
+
252
+ If a v8 escape hatch was needed because of a bug or missing API, check the v9
253
+ public API first — many things were added in v9.
254
+
255
+ ### `ColumnMeta` augmentation without the `TFeatures` generic
256
+
257
+ The interface now takes `TFeatures` first. Old declarations get silently merged
258
+ but typed wrong.
259
+
260
+ ### Importing `flexRender` as a function
261
+
262
+ There's no `flexRender(fn, ctx)` in Angular. `FlexRender` is a directive tuple
263
+ constant. Imports + template directive form is the only shape.
264
+
265
+ ### Trying to share v9 atoms with v8 — incompatible
266
+
267
+ If you have a partial v8 codebase coexisting, **don't** try to bridge atoms
268
+ across the version boundary. Migrate per-component.