@tanstack/vue-table 9.0.0-beta.40 → 9.0.0-beta.43

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.
@@ -1,399 +0,0 @@
1
- ---
2
- name: vue/table-state
3
- description: >
4
- Vue reactivity for `@tanstack/vue-table` v9. Covers `useTable(options, selector?)`, reactive
5
- `data`/`columns` via `ref`/`computed` getters, the `vueReactivity()` binding (readonly atoms →
6
- `computed`, writable → `shallowRef`, subscriptions via `watch({flush:'sync'})`), the three state
7
- surfaces `table.atoms.<slice>` / `table.store` / `table.state`, selected state via the second
8
- `useTable` argument, the `<FlexRender>` component, `table.Subscribe` for atom/source subscriptions,
9
- and composition with `createAtom` / `useSelector` from `@tanstack/vue-store`.
10
- type: framework
11
- library: tanstack-table
12
- framework: vue
13
- library_version: '9.0.0-alpha.48'
14
- requires:
15
- - state-management
16
- - setup
17
- sources:
18
- - docs/framework/vue/guide/table-state.md
19
- - docs/framework/vue/vue-table.md
20
- - packages/vue-table/src/useTable.ts
21
- - packages/vue-table/src/reactivity.ts
22
- - packages/vue-table/src/FlexRender.ts
23
- - examples/vue/basic-use-table/
24
- - examples/vue/basic-external-atoms/
25
- - examples/vue/basic-external-state/
26
- ---
27
-
28
- # Vue Table State, Subscribe & createTableHook
29
-
30
- ## Dependencies
31
-
32
- ```bash
33
- pnpm add @tanstack/vue-table @tanstack/vue-store
34
- ```
35
-
36
- `@tanstack/vue-store` is a peer for `createAtom` / `useSelector`. It is only required when you
37
- opt into external atoms — basic tables that use `initialState` or built-in state work without it.
38
-
39
- This skill is v9-specific (`9.0.0-alpha.48`). The hook is `useTable` for every framework now; the
40
- v8 name `useVueTable` no longer exists.
41
-
42
- ## Setup
43
-
44
- Every Vue table call requires `features` (built from `tableFeatures({...})`). Row model
45
- factories now live on the features object alongside the feature itself. Core row model is
46
- automatic; only register `paginatedRowModel`, `sortedRowModel`, etc. when you use the matching
47
- feature.
48
-
49
- ```vue
50
- <script setup lang="ts">
51
- import { ref } from 'vue'
52
- import {
53
- FlexRender,
54
- createColumnHelper,
55
- createSortedRowModel,
56
- rowSortingFeature,
57
- sortFns,
58
- tableFeatures,
59
- useTable,
60
- } from '@tanstack/vue-table'
61
-
62
- type Person = { firstName: string; lastName: string; age: number }
63
-
64
- // Stable identity — declare outside the component or at module scope.
65
- const features = tableFeatures({
66
- rowSortingFeature,
67
- sortedRowModel: createSortedRowModel(),
68
- sortFns,
69
- })
70
- const columnHelper = createColumnHelper<typeof features, Person>()
71
- const columns = columnHelper.columns([
72
- columnHelper.accessor('firstName', { header: 'First' }),
73
- columnHelper.accessor('lastName', { header: 'Last' }),
74
- columnHelper.accessor('age', { header: 'Age' }),
75
- ])
76
-
77
- const data = ref<Person[]>([])
78
-
79
- const table = useTable({
80
- features,
81
- columns,
82
- // Reactive data: pass the ref directly OR a getter — the adapter unwraps.
83
- data,
84
- })
85
- </script>
86
-
87
- <template>
88
- <table>
89
- <thead>
90
- <tr v-for="hg in table.getHeaderGroups()" :key="hg.id">
91
- <th v-for="h in hg.headers" :key="h.id">
92
- <FlexRender v-if="!h.isPlaceholder" :header="h" />
93
- </th>
94
- </tr>
95
- </thead>
96
- <tbody>
97
- <tr v-for="row in table.getRowModel().rows" :key="row.id">
98
- <td v-for="cell in row.getAllCells()" :key="cell.id">
99
- <FlexRender :cell="cell" />
100
- </td>
101
- </tr>
102
- </tbody>
103
- </table>
104
- </template>
105
- ```
106
-
107
- ### Why this works
108
-
109
- The Vue adapter calls `vueReactivity()` and installs it as `coreReactivityFeature` automatically
110
- (see `packages/vue-table/src/useTable.ts`):
111
-
112
- - Readonly atoms back onto `computed()` refs.
113
- - Writable atoms back onto `shallowRef()`.
114
- - Subscriptions use `watch(source, cb, { flush: 'sync' })`, so table updates are visible to Vue
115
- render and computed work immediately.
116
-
117
- `useTable` also runs a `watch(() => getReactiveOptionDeps(...))` on every option, so passing a
118
- `ref` or `computed` for `data`, `columns`, `rowCount`, etc. is supported — the table calls
119
- `setOptions` whenever any reactive option changes.
120
-
121
- > **Vue note.** `table.Subscribe` exists for parity with React, but you usually do not need it.
122
- > Vue's reactivity re-evaluates template reads automatically — wrap reads in `computed(...)` if
123
- > you need them outside a template. Do not import React-Compiler workarounds.
124
-
125
- ## Core Patterns
126
-
127
- ### 1. The three read surfaces
128
-
129
- ```ts
130
- // (a) Per-slice atom — narrowest, no full state snapshot built
131
- const sorting = table.atoms.sorting.get()
132
-
133
- // (b) Flat readonly store — every registered slice as one object
134
- const snapshot = table.state
135
-
136
- // (c) Vue selected state — the value returned from useTable's 2nd arg
137
- const table = useTable(
138
- {
139
- features,
140
- columns,
141
- data,
142
- },
143
- (state) => ({ sorting: state.sorting }),
144
- )
145
- table.state.sorting // typed, reactive
146
- ```
147
-
148
- `table.atoms.<slice>` only contains slices for features registered in `features`. If
149
- `rowSortingFeature` is not registered, `table.atoms.sorting` is `undefined` (and TypeScript
150
- flags it). This is the v9-specific "missing API" gotcha — register the feature first.
151
-
152
- Source: `docs/framework/vue/guide/table-state.md` (Feature-based State, Accessing Table State).
153
-
154
- ### 2. Reactive data with a getter or computed
155
-
156
- The adapter accepts a `ref`/`computed` for any option. The idiomatic shapes are:
157
-
158
- ```ts
159
- // (a) Pass the ref directly — adapter unwraps via `unref()`
160
- const data = ref(makeData(100))
161
- const table = useTable({ features, columns, data })
162
-
163
- // (b) Use a getter when `data` is owned by a parent object
164
- const table = useTable({
165
- features,
166
- columns,
167
- get data() {
168
- return data.value
169
- },
170
- })
171
-
172
- // (c) Computed when filtering/derivation lives on the client
173
- const filtered = computed(() => data.value.filter(/* … */))
174
- const table = useTable({
175
- features,
176
- columns,
177
- get data() {
178
- return filtered.value
179
- },
180
- })
181
- ```
182
-
183
- When `data.value` changes, `useTable` calls `setOptions` synchronously and the table re-derives.
184
- Source: `examples/vue/basic-use-table/src/App.tsx`, `examples/vue/virtualized-rows/src/App.vue`.
185
-
186
- ### 3. External atoms (recommended for shared state)
187
-
188
- Use `createAtom` from `@tanstack/vue-store`; pass through `options.atoms`. Atoms take
189
- precedence over `options.state` — pick one mechanism per slice.
190
-
191
- ```vue
192
- <script setup lang="ts">
193
- import { ref } from 'vue'
194
- import { createAtom, useSelector } from '@tanstack/vue-store'
195
- import {
196
- createPaginatedRowModel,
197
- rowPaginationFeature,
198
- tableFeatures,
199
- useTable,
200
- type PaginationState,
201
- } from '@tanstack/vue-table'
202
-
203
- const features = tableFeatures({
204
- rowPaginationFeature,
205
- paginatedRowModel: createPaginatedRowModel(),
206
- })
207
-
208
- const paginationAtom = createAtom<PaginationState>({
209
- pageIndex: 0,
210
- pageSize: 10,
211
- })
212
- const pagination = useSelector(paginationAtom) // reactive ref-like
213
-
214
- const data = ref([] as Person[])
215
- const table = useTable({
216
- features,
217
- columns,
218
- data,
219
- atoms: { pagination: paginationAtom },
220
- // NOTE: no `onPaginationChange` — `table.setPageIndex()` writes through to the atom.
221
- })
222
- </script>
223
-
224
- <template>
225
- <button @click="table.nextPage()" :disabled="!table.getCanNextPage()">
226
- Next
227
- </button>
228
- <span>Page {{ pagination.value.pageIndex + 1 }}</span>
229
- </template>
230
- ```
231
-
232
- Source: `examples/vue/basic-external-atoms/src/App.tsx`.
233
-
234
- ### 4. External `state` + `on[State]Change` with getters
235
-
236
- Still supported and convenient for migration paths. The critical rule: pass each slice as a
237
- **getter** so Vue can track `.value` changes. A raw ref captured in the state object is read
238
- once and never re-tracked.
239
-
240
- ```ts
241
- const sorting = ref<SortingState>([])
242
- const pagination = ref<PaginationState>({ pageIndex: 0, pageSize: 10 })
243
-
244
- const table = useTable({
245
- features,
246
- columns,
247
- data,
248
- state: {
249
- get sorting() {
250
- return sorting.value
251
- }, // <- getter
252
- get pagination() {
253
- return pagination.value
254
- }, // <- getter
255
- },
256
- onSortingChange: (u) => {
257
- sorting.value = typeof u === 'function' ? u(sorting.value) : u
258
- },
259
- onPaginationChange: (u) => {
260
- pagination.value = typeof u === 'function' ? u(pagination.value) : u
261
- },
262
- })
263
- ```
264
-
265
- Source: `examples/vue/basic-external-state/src/App.tsx`,
266
- `docs/framework/vue/guide/table-state.md` (External State).
267
-
268
- ### 5. `<FlexRender>` and `table.Subscribe`
269
-
270
- `<FlexRender>` accepts a `cell`, `header`, or `footer` prop (preferred). The legacy
271
- `:render` / `:props` pattern still works.
272
-
273
- ```vue
274
- <FlexRender :cell="cell" />
275
- <FlexRender :header="header" />
276
- <FlexRender :footer="header" />
277
-
278
- <!-- Legacy form -->
279
- <FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
280
- ```
281
-
282
- `table.Subscribe` mostly mirrors React. It is rarely the right tool in Vue — prefer
283
- `computed(() => table.atoms.<slice>.get())` or the `useTable` selector. If you do need it
284
- (for cross-store source subscription), it accepts a `source` prop:
285
-
286
- ```ts
287
- // In a render function or JSX file
288
- return () => (
289
- <table.Subscribe source={someAtom} selector={(v) => v.someField}>
290
- {(value) => <span>{value}</span>}
291
- </table.Subscribe>
292
- )
293
- ```
294
-
295
- ## Common Mistakes
296
-
297
- ### Passing a `ref` to `state.pagination` without a getter (CRITICAL)
298
-
299
- ```ts
300
- // ❌ Captures the ref object; later `pagination.value = …` writes are invisible.
301
- const pagination = ref<PaginationState>({ pageIndex: 0, pageSize: 10 })
302
- const table = useTable({
303
- features,
304
- columns,
305
- data,
306
- state: { pagination },
307
- })
308
-
309
- // ✅ Use a getter so Vue tracks `.value`.
310
- const table = useTable({
311
- features,
312
- columns,
313
- data,
314
- state: {
315
- get pagination() {
316
- return pagination.value
317
- },
318
- },
319
- onPaginationChange: (u) => {
320
- pagination.value = typeof u === 'function' ? u(pagination.value) : u
321
- },
322
- })
323
- ```
324
-
325
- Source: `docs/framework/vue/guide/table-state.md` (External State).
326
-
327
- ### Reading `table.atoms.<slice>.get()` outside a reactive context (HIGH)
328
-
329
- ```ts
330
- // ❌ One-shot read at component setup — never updates.
331
- const pagination = table.atoms.pagination.get()
332
-
333
- // ✅ Wrap in `computed` so Vue tracks the atom.
334
- const pagination = computed(() => table.atoms.pagination.get())
335
- // or
336
- const table = useTable(opts, (s) => ({ pagination: s.pagination }))
337
- // then read `table.state.pagination`
338
- ```
339
-
340
- ### Using the v8 `useVueTable` name (HIGH)
341
-
342
- ```ts
343
- // ❌ Removed in v9.
344
- import { useVueTable } from '@tanstack/vue-table'
345
-
346
- // ✅
347
- import { useTable } from '@tanstack/vue-table'
348
- ```
349
-
350
- ### "API missing" because the feature is not in `features` (CRITICAL, v9-specific)
351
-
352
- ```ts
353
- // ❌ `rowSortingFeature` not registered → `table.setSorting` and `table.atoms.sorting` do not exist.
354
- const features = tableFeatures({})
355
- const table = useTable({ features, columns, data })
356
- table.setSorting([{ id: 'age', desc: true }]) // TS error / runtime no-op
357
-
358
- // ✅ Register the feature and its matching row model factory inside tableFeatures.
359
- const features = tableFeatures({
360
- rowSortingFeature,
361
- sortedRowModel: createSortedRowModel(),
362
- sortFns,
363
- })
364
- const table = useTable({ features, columns, data })
365
- ```
366
-
367
- ### Reimplementing built-in state transitions (CRITICAL — #1 AI tell)
368
-
369
- ```ts
370
- // ❌ Hand-rolled sort — bypasses the table's invariants and reset APIs.
371
- const sorting = ref<SortingState>([])
372
- const sorted = computed(() => [...data.value].sort(/* … */))
373
-
374
- // ✅ Let the table own it. Use `table.setSorting`, `column.toggleSorting`,
375
- // `header.column.getToggleSortingHandler()`.
376
- ```
377
-
378
- The library exposes `setSorting`, `setColumnFilters`, `toggleSelected`, `nextPage`, etc. for
379
- nearly every state transition.
380
-
381
- ### Hallucinating pre-v9 API names
382
-
383
- `useVueTable`, `getCoreRowModel()` as an option, `createColumnHelper<TData>()` (single generic),
384
- `sortingFn` instead of `sortFn` — all v8 shapes that will not compile. See
385
- `migrate-v8-to-v9` for the full rename list.
386
-
387
- ### Unstable `features` / `columns` / `data` identity
388
-
389
- Declare `features`, `columnHelper`, and `columns` **outside** `<script setup>` (at module
390
- scope) or use `computed`. Recreating them every render churns the table's option diff watcher
391
- and triggers a `setOptions` on every render — slow, and external atom slices can flicker.
392
-
393
- ## See Also
394
-
395
- - `tanstack-table/vue/getting-started` — the end-to-end first-table walkthrough
396
- - `tanstack-table/vue/production-readiness` — selectors, tree-shaking, identity
397
- - `tanstack-table/vue/compose-with-tanstack-store` — external atoms in depth
398
- - `tanstack-table/table-core/state-management` (core) — the atom model that drives this skill
399
- - `tanstack-table/vue/migrate-v8-to-v9` — `useVueTable` → `useTable`