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

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