@tanstack/svelte-table 9.0.0-alpha.47 → 9.0.0-alpha.49
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.
- package/README.md +10 -0
- package/package.json +7 -5
- package/skills/svelte/client-to-server/SKILL.md +238 -0
- package/skills/svelte/compose-with-tanstack-form/SKILL.md +295 -0
- package/skills/svelte/compose-with-tanstack-pacer/SKILL.md +176 -0
- package/skills/svelte/compose-with-tanstack-query/SKILL.md +299 -0
- package/skills/svelte/compose-with-tanstack-store/SKILL.md +277 -0
- package/skills/svelte/compose-with-tanstack-virtual/SKILL.md +286 -0
- package/skills/svelte/getting-started/SKILL.md +340 -0
- package/skills/svelte/migrate-v8-to-v9/SKILL.md +256 -0
- package/skills/svelte/production-readiness/SKILL.md +256 -0
- package/skills/svelte/table-state/SKILL.md +441 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: svelte/getting-started
|
|
3
|
+
description: >
|
|
4
|
+
End-to-end first-table journey for `@tanstack/svelte-table@9` on Svelte 5. Install the adapter,
|
|
5
|
+
declare `_features` with `tableFeatures()`, register `_rowModels` factories with their `*Fns`
|
|
6
|
+
parameters, build a typed column helper with both `TFeatures` and `TData` generics, instantiate
|
|
7
|
+
the table with `createTable(options)` using `$state` data and `get data()` reactive option getters,
|
|
8
|
+
and render with `FlexRender`. Svelte 5+ only — Svelte 3/4 must use v8.
|
|
9
|
+
type: lifecycle
|
|
10
|
+
library: tanstack-table
|
|
11
|
+
framework: svelte
|
|
12
|
+
library_version: '9.0.0-alpha.48'
|
|
13
|
+
requires:
|
|
14
|
+
- setup
|
|
15
|
+
- column-definitions
|
|
16
|
+
- state-management
|
|
17
|
+
- svelte/table-state
|
|
18
|
+
sources:
|
|
19
|
+
- TanStack/table:docs/installation.md
|
|
20
|
+
- TanStack/table:docs/framework/svelte/svelte-table.md
|
|
21
|
+
- TanStack/table:examples/svelte/basic-create-table/
|
|
22
|
+
- TanStack/table:examples/svelte/basic-app-table/
|
|
23
|
+
- TanStack/table:examples/svelte/basic-snippets/
|
|
24
|
+
- TanStack/table:packages/svelte-table/src/index.ts
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Getting Started — Svelte
|
|
28
|
+
|
|
29
|
+
A first working `@tanstack/svelte-table` v9 table from a blank Svelte 5 project. Read this
|
|
30
|
+
end-to-end before searching the docs — the v9 shape diverges enough from v8 (and from your
|
|
31
|
+
muscle memory) that skimming will produce broken code.
|
|
32
|
+
|
|
33
|
+
## CRITICAL: Svelte version
|
|
34
|
+
|
|
35
|
+
**`@tanstack/svelte-table@9` requires Svelte 5 or newer.** The adapter is built on runes
|
|
36
|
+
(`$state`, `$derived.by`, `$effect.pre`). If your project is on Svelte 3 or 4, do **one** of:
|
|
37
|
+
|
|
38
|
+
- Upgrade the project to Svelte 5, then install v9.
|
|
39
|
+
- Stay on `@tanstack/svelte-table@8` for that project.
|
|
40
|
+
|
|
41
|
+
There is no shim, no `/legacy` export, and no support path that runs v9 on Svelte 4.
|
|
42
|
+
|
|
43
|
+
## 1. Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pnpm add @tanstack/svelte-table
|
|
47
|
+
# optional: external atoms / fine-grained selectors
|
|
48
|
+
pnpm add @tanstack/svelte-store
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
You do **not** install `@tanstack/table-core` separately — the Svelte adapter re-exports
|
|
52
|
+
everything you need (column helpers, feature objects, row-model factories, types).
|
|
53
|
+
|
|
54
|
+
## 2. Define `_features` and `_rowModels`
|
|
55
|
+
|
|
56
|
+
v9 is explicit. You opt in to every feature and every row model. The core row model is
|
|
57
|
+
included by default, so the minimum viable table is:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const _features = tableFeatures({})
|
|
61
|
+
const _rowModels = {}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
For anything beyond a flat table, register the features you'll use **and** the matching
|
|
65
|
+
row-model factories. Row-model factories take `*Fns` registries as parameters:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import {
|
|
69
|
+
columnFilteringFeature,
|
|
70
|
+
createFilteredRowModel,
|
|
71
|
+
createPaginatedRowModel,
|
|
72
|
+
createSortedRowModel,
|
|
73
|
+
filterFns,
|
|
74
|
+
rowPaginationFeature,
|
|
75
|
+
rowSortingFeature,
|
|
76
|
+
sortFns,
|
|
77
|
+
tableFeatures,
|
|
78
|
+
} from '@tanstack/svelte-table'
|
|
79
|
+
|
|
80
|
+
const _features = tableFeatures({
|
|
81
|
+
rowPaginationFeature,
|
|
82
|
+
rowSortingFeature,
|
|
83
|
+
columnFilteringFeature,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const _rowModels = {
|
|
87
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
88
|
+
sortedRowModel: createSortedRowModel(sortFns),
|
|
89
|
+
filteredRowModel: createFilteredRowModel(filterFns),
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Skipping a feature** in `_features` means its state slice does not exist on `table.atoms`,
|
|
94
|
+
its options on `createTable` do nothing, and its derived APIs (`table.setSorting`,
|
|
95
|
+
`column.getCanSort`) are not on the instance.
|
|
96
|
+
|
|
97
|
+
## 3. Type your data and define columns
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
type Person = {
|
|
101
|
+
firstName: string
|
|
102
|
+
lastName: string
|
|
103
|
+
age: number
|
|
104
|
+
visits: number
|
|
105
|
+
status: 'relationship' | 'complicated' | 'single'
|
|
106
|
+
progress: number
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Both `ColumnDef` and the column helper take the two generics `<typeof _features, TData>`:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { createColumnHelper, type ColumnDef } from '@tanstack/svelte-table'
|
|
114
|
+
|
|
115
|
+
const columnHelper = createColumnHelper<typeof _features, Person>()
|
|
116
|
+
|
|
117
|
+
const columns = columnHelper.columns([
|
|
118
|
+
columnHelper.accessor('firstName', {
|
|
119
|
+
header: 'First Name',
|
|
120
|
+
cell: (info) => info.getValue(),
|
|
121
|
+
}),
|
|
122
|
+
columnHelper.accessor((row) => row.lastName, {
|
|
123
|
+
id: 'lastName',
|
|
124
|
+
header: () => 'Last Name',
|
|
125
|
+
cell: (info) => info.getValue(),
|
|
126
|
+
}),
|
|
127
|
+
columnHelper.accessor('age', { header: 'Age' }),
|
|
128
|
+
columnHelper.accessor('visits', { header: 'Visits' }),
|
|
129
|
+
columnHelper.accessor('status', { header: 'Status' }),
|
|
130
|
+
columnHelper.accessor('progress', { header: 'Profile Progress' }),
|
|
131
|
+
])
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Or use raw `ColumnDef` arrays if you don't want the helper:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const columns: Array<ColumnDef<typeof _features, Person>> = [
|
|
138
|
+
{
|
|
139
|
+
accessorKey: 'firstName',
|
|
140
|
+
header: 'First Name',
|
|
141
|
+
cell: (info) => info.getValue(),
|
|
142
|
+
},
|
|
143
|
+
]
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 4. Create the table
|
|
147
|
+
|
|
148
|
+
Use Svelte 5 `$state` for the data and pass it through a **reactive getter** so the table
|
|
149
|
+
re-evaluates `data` when the rune changes. The same pattern applies for any other reactive
|
|
150
|
+
option (`columns`, `rowCount`, `state.*`).
|
|
151
|
+
|
|
152
|
+
```svelte
|
|
153
|
+
<script lang="ts">
|
|
154
|
+
import { createTable, tableFeatures } from '@tanstack/svelte-table'
|
|
155
|
+
import { makeData, type Person } from './makeData'
|
|
156
|
+
|
|
157
|
+
const _features = tableFeatures({})
|
|
158
|
+
|
|
159
|
+
// ... columns from step 3 ...
|
|
160
|
+
|
|
161
|
+
let data = $state<Person[]>(makeData(20))
|
|
162
|
+
|
|
163
|
+
const refreshData = () => {
|
|
164
|
+
data = makeData(20)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const table = createTable({
|
|
168
|
+
_features,
|
|
169
|
+
_rowModels: {},
|
|
170
|
+
columns,
|
|
171
|
+
get data() {
|
|
172
|
+
return data
|
|
173
|
+
},
|
|
174
|
+
})
|
|
175
|
+
</script>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`createTable` syncs options inside `$effect.pre`, so external `$state` updates flow into the
|
|
179
|
+
table **before** the DOM reads `getRowModel()` — no stale-frame bugs.
|
|
180
|
+
|
|
181
|
+
## 5. Render with `FlexRender`
|
|
182
|
+
|
|
183
|
+
`FlexRender` handles plain strings, function renderers, component renderers
|
|
184
|
+
(`renderComponent`), and snippet renderers (`renderSnippet`).
|
|
185
|
+
|
|
186
|
+
```svelte
|
|
187
|
+
<script lang="ts">
|
|
188
|
+
import { FlexRender } from '@tanstack/svelte-table'
|
|
189
|
+
</script>
|
|
190
|
+
|
|
191
|
+
<button onclick={refreshData}>Regenerate</button>
|
|
192
|
+
|
|
193
|
+
<table>
|
|
194
|
+
<thead>
|
|
195
|
+
{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
|
|
196
|
+
<tr>
|
|
197
|
+
{#each headerGroup.headers as header (header.id)}
|
|
198
|
+
<th>
|
|
199
|
+
{#if !header.isPlaceholder}
|
|
200
|
+
<FlexRender {header} />
|
|
201
|
+
{/if}
|
|
202
|
+
</th>
|
|
203
|
+
{/each}
|
|
204
|
+
</tr>
|
|
205
|
+
{/each}
|
|
206
|
+
</thead>
|
|
207
|
+
<tbody>
|
|
208
|
+
{#each table.getRowModel().rows as row (row.id)}
|
|
209
|
+
<tr>
|
|
210
|
+
{#each row.getAllCells() as cell (cell.id)}
|
|
211
|
+
<td><FlexRender {cell} /></td>
|
|
212
|
+
{/each}
|
|
213
|
+
</tr>
|
|
214
|
+
{/each}
|
|
215
|
+
</tbody>
|
|
216
|
+
</table>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Key the `{#each}` blocks on stable ids.** Without keys, Svelte recreates nodes and loses
|
|
220
|
+
focus, scroll, and any per-row component state.
|
|
221
|
+
|
|
222
|
+
## 6. Adding a feature — pagination
|
|
223
|
+
|
|
224
|
+
```svelte
|
|
225
|
+
<script lang="ts">
|
|
226
|
+
import {
|
|
227
|
+
createPaginatedRowModel,
|
|
228
|
+
createTable,
|
|
229
|
+
rowPaginationFeature,
|
|
230
|
+
tableFeatures,
|
|
231
|
+
} from '@tanstack/svelte-table'
|
|
232
|
+
|
|
233
|
+
const _features = tableFeatures({ rowPaginationFeature })
|
|
234
|
+
|
|
235
|
+
const table = createTable({
|
|
236
|
+
_features,
|
|
237
|
+
_rowModels: {
|
|
238
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
239
|
+
},
|
|
240
|
+
columns,
|
|
241
|
+
get data() {
|
|
242
|
+
return data
|
|
243
|
+
},
|
|
244
|
+
initialState: {
|
|
245
|
+
pagination: { pageIndex: 0, pageSize: 10 },
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
</script>
|
|
249
|
+
|
|
250
|
+
<div>
|
|
251
|
+
<button
|
|
252
|
+
onclick={() => table.previousPage()}
|
|
253
|
+
disabled={!table.getCanPreviousPage()}>Prev</button
|
|
254
|
+
>
|
|
255
|
+
<span
|
|
256
|
+
>Page {table.atoms.pagination.get().pageIndex + 1} of {table.getPageCount()}</span
|
|
257
|
+
>
|
|
258
|
+
<button onclick={() => table.nextPage()} disabled={!table.getCanNextPage()}
|
|
259
|
+
>Next</button
|
|
260
|
+
>
|
|
261
|
+
</div>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
To make pagination reactive in the controls, either pass a selector to `createTable` or use
|
|
265
|
+
`subscribeTable`:
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
import { subscribeTable } from '@tanstack/svelte-table'
|
|
269
|
+
|
|
270
|
+
const pagination = subscribeTable(table.atoms.pagination)
|
|
271
|
+
// pagination.current.pageIndex is reactive
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## 7. `createTableHook` (when you have more than one table)
|
|
275
|
+
|
|
276
|
+
For apps with multiple tables, define the `_features`, `_rowModels`, and shared components
|
|
277
|
+
once:
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
// hooks/table.ts
|
|
281
|
+
import {
|
|
282
|
+
createPaginatedRowModel,
|
|
283
|
+
createSortedRowModel,
|
|
284
|
+
createTableHook,
|
|
285
|
+
rowPaginationFeature,
|
|
286
|
+
rowSortingFeature,
|
|
287
|
+
sortFns,
|
|
288
|
+
tableFeatures,
|
|
289
|
+
} from '@tanstack/svelte-table'
|
|
290
|
+
|
|
291
|
+
export const { createAppTable, createAppColumnHelper } = createTableHook({
|
|
292
|
+
_features: tableFeatures({ rowPaginationFeature, rowSortingFeature }),
|
|
293
|
+
_rowModels: {
|
|
294
|
+
paginatedRowModel: createPaginatedRowModel(),
|
|
295
|
+
sortedRowModel: createSortedRowModel(sortFns),
|
|
296
|
+
},
|
|
297
|
+
})
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
```svelte
|
|
301
|
+
<script lang="ts">
|
|
302
|
+
import { createAppColumnHelper, createAppTable } from './hooks/table'
|
|
303
|
+
|
|
304
|
+
const columnHelper = createAppColumnHelper<Person>()
|
|
305
|
+
const columns = columnHelper.columns([
|
|
306
|
+
columnHelper.accessor('firstName', { header: 'First' }),
|
|
307
|
+
])
|
|
308
|
+
|
|
309
|
+
const table = createAppTable({
|
|
310
|
+
columns,
|
|
311
|
+
get data() {
|
|
312
|
+
return data
|
|
313
|
+
},
|
|
314
|
+
})
|
|
315
|
+
</script>
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Common failure modes
|
|
319
|
+
|
|
320
|
+
- **Svelte 3/4.** Adapter will not work. See top of file.
|
|
321
|
+
- **`createSvelteTable` / `useSvelteTable` / `getCoreRowModel`** — all v8 names. v9 uses
|
|
322
|
+
`createTable` and `_rowModels: { paginatedRowModel: createPaginatedRowModel(), ... }`.
|
|
323
|
+
- **Plain `data` instead of `get data()` getter.** Table will not see data updates. Always
|
|
324
|
+
pass a reactive getter for state that lives in `$state`.
|
|
325
|
+
- **Missing feature in `_features`.** `table.setSorting` / `column.getCanSort` won't exist.
|
|
326
|
+
TypeScript will tell you; if it doesn't, you're missing the `<typeof _features, TData>`
|
|
327
|
+
generics on the column helper or `ColumnDef`.
|
|
328
|
+
- **Plain object instead of `tableFeatures({...})`.** Loses typed atom keys; you'll get
|
|
329
|
+
`unknown` state shapes everywhere.
|
|
330
|
+
- **Unkeyed `{#each}` blocks.** Reuse bugs (focus jumps, wrong row selected).
|
|
331
|
+
- **Reimplementing built-ins.** If you write a manual sort comparator across rows, you're
|
|
332
|
+
re-doing `rowSortingFeature`. Register it instead.
|
|
333
|
+
|
|
334
|
+
## Next steps
|
|
335
|
+
|
|
336
|
+
- `tanstack-table/svelte/table-state` — reactivity model, selectors, subscribeTable, ownership.
|
|
337
|
+
- `tanstack-table/core/filtering` / `pagination` / `sorting` / `row-selection` — feature-by-feature.
|
|
338
|
+
- `tanstack-table/svelte/compose-with-tanstack-query` — server-side data.
|
|
339
|
+
- `tanstack-table/svelte/compose-with-tanstack-virtual` — large datasets.
|
|
340
|
+
- `tanstack-table/svelte/production-readiness` — selector tuning, bundle size.
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: svelte/migrate-v8-to-v9
|
|
3
|
+
description: >
|
|
4
|
+
Mechanical migration from `@tanstack/svelte-table@8` to `@tanstack/svelte-table@9`. v9 in Svelte
|
|
5
|
+
is a full rewrite — Svelte 5 runes only (no Svelte 3/4), no `/legacy` adapter (unlike React),
|
|
6
|
+
`createSvelteTable` → `createTable`, `getCoreRowModel` / `getSortedRowModel` factories → required
|
|
7
|
+
`_features` + `_rowModels` registration, `flexRender` helper → `<FlexRender>` component,
|
|
8
|
+
writable-store `state` → rune-based getters / external atoms, `onStateChange` → per-slice
|
|
9
|
+
`on[State]Change` or `atoms`. Plan a feature-by-feature audit, not a search-and-replace.
|
|
10
|
+
type: lifecycle
|
|
11
|
+
library: tanstack-table
|
|
12
|
+
framework: svelte
|
|
13
|
+
library_version: '9.0.0-alpha.48'
|
|
14
|
+
requires:
|
|
15
|
+
- setup
|
|
16
|
+
- state-management
|
|
17
|
+
- column-definitions
|
|
18
|
+
sources:
|
|
19
|
+
- TanStack/table:docs/framework/svelte/svelte-table.md
|
|
20
|
+
- TanStack/table:docs/framework/svelte/guide/table-state.md
|
|
21
|
+
- TanStack/table:packages/svelte-table/src/
|
|
22
|
+
- TanStack/table:examples/svelte/basic-create-table/
|
|
23
|
+
- TanStack/table:examples/svelte/basic-external-atoms/
|
|
24
|
+
- TanStack/table:examples/svelte/basic-external-state/
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# Migrate v8 → v9 (Svelte)
|
|
28
|
+
|
|
29
|
+
## CRITICAL: v9 = Svelte 5
|
|
30
|
+
|
|
31
|
+
**v9 of the Svelte adapter only supports Svelte 5+.** No backport. No shim. No `/legacy` import.
|
|
32
|
+
The v9 adapter is built on Svelte 5 runes (`$state`, `$derived.by`, `$effect.pre`). If your app
|
|
33
|
+
is still on Svelte 3/4, you have two real options:
|
|
34
|
+
|
|
35
|
+
1. Stay on `@tanstack/svelte-table@8`. v8 keeps working with the Svelte 3/4 writable-store API.
|
|
36
|
+
2. Migrate the app to Svelte 5 first, then migrate the table.
|
|
37
|
+
|
|
38
|
+
There is no third option. Trying to install v9 on a Svelte 4 codebase will error at compile.
|
|
39
|
+
|
|
40
|
+
> This makes the Svelte migration heavier than React's. React has a `/legacy` re-export that
|
|
41
|
+
> mirrors the v8 surface; Svelte does not. Plan for a real rewrite of every table screen.
|
|
42
|
+
|
|
43
|
+
## What changed at the type / API level
|
|
44
|
+
|
|
45
|
+
| v8 | v9 |
|
|
46
|
+
| -------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
47
|
+
| `createSvelteTable(options)` | `createTable(options, selector?)` |
|
|
48
|
+
| `getCoreRowModel()` | included by default; no factory |
|
|
49
|
+
| `getPaginationRowModel()` | `_rowModels.paginatedRowModel: createPaginatedRowModel()` |
|
|
50
|
+
| `getSortedRowModel()` | `_rowModels.sortedRowModel: createSortedRowModel(sortFns)` |
|
|
51
|
+
| `getFilteredRowModel()` | `_rowModels.filteredRowModel: createFilteredRowModel(filterFns)` |
|
|
52
|
+
| `getExpandedRowModel()` | `_rowModels.expandedRowModel: createExpandedRowModel()` |
|
|
53
|
+
| `getGroupedRowModel()` | `_rowModels.groupedRowModel: createGroupedRowModel(aggregationFns)` |
|
|
54
|
+
| `getFacetedRowModel()` / `MinMax` / `UniqueValues` | facet APIs auto-derived when `*Facet*Feature` registered |
|
|
55
|
+
| `flexRender(template, ctx)` helper | `<FlexRender header={h} />` / `<FlexRender cell={c} />` / `<FlexRender footer={h} />` |
|
|
56
|
+
| `ColumnDef<TData>` | `ColumnDef<TFeatures, TData>` (extra generic) |
|
|
57
|
+
| `createColumnHelper<TData>()` | `createColumnHelper<TFeatures, TData>()` |
|
|
58
|
+
| writable store on the table instance | `table.atoms.<slice>` + `table.store` + `table.state` |
|
|
59
|
+
| `onStateChange` (monolithic) | per-slice `on[State]Change`, or external `atoms` |
|
|
60
|
+
| `useSvelteTable` (rare) | gone |
|
|
61
|
+
|
|
62
|
+
## What did NOT change
|
|
63
|
+
|
|
64
|
+
- The data array is still the source of truth; columns are still defined the same way
|
|
65
|
+
shape-wise (`accessorKey` / `accessorFn` / `header` / `cell` / `footer`).
|
|
66
|
+
- Filter, sort, aggregation function registries are still `filterFns`, `sortFns`,
|
|
67
|
+
`aggregationFns` — but now passed into row-model factories instead of being auto-resolved.
|
|
68
|
+
- Feature APIs (`table.nextPage()`, `column.getCanSort()`, `row.toggleSelected()`) keep the
|
|
69
|
+
same names.
|
|
70
|
+
|
|
71
|
+
## Migration checklist (per file)
|
|
72
|
+
|
|
73
|
+
For each Svelte component that uses the table:
|
|
74
|
+
|
|
75
|
+
1. **Upgrade Svelte.** Ensure the app is on Svelte 5 and the component compiles in runes mode.
|
|
76
|
+
2. **Replace store with rune.** `let data = writable([])` → `let data = $state([])`. Reads
|
|
77
|
+
inside markup are no longer `$data` — just `data`.
|
|
78
|
+
3. **Import surface.** `import { createSvelteTable, getCoreRowModel, flexRender }` →
|
|
79
|
+
`import { createTable, FlexRender, tableFeatures, ... }`.
|
|
80
|
+
4. **Add `_features`.** Create `const _features = tableFeatures({ ... only the features this
|
|
81
|
+
table uses ... })`.
|
|
82
|
+
5. **Move row-model factories.** Every `get*RowModel: get*RowModel()` becomes a `_rowModels`
|
|
83
|
+
entry with the matching `create*RowModel(*Fns)` factory.
|
|
84
|
+
6. **Generic columns.** Add `<typeof _features, TData>` to `ColumnDef<>` and
|
|
85
|
+
`createColumnHelper<>()`. TypeScript will tell you when you missed one.
|
|
86
|
+
7. **`data` as a getter.** `data: data` → `get data() { return data }`. Same for any other
|
|
87
|
+
reactive option (`state.*`, `columns`, `rowCount`).
|
|
88
|
+
8. **State.** Pick the new ownership model — see below.
|
|
89
|
+
9. **Rendering.** `{flexRender(header.column.columnDef.header, header.getContext())}` →
|
|
90
|
+
`<FlexRender header={header} />`. Same for cells and footers.
|
|
91
|
+
10. **Components / snippets in cells.** v8: pass a Svelte component constructor. v9: wrap with
|
|
92
|
+
`renderComponent(MyCell, props)` or `renderSnippet(snippet, args)`.
|
|
93
|
+
|
|
94
|
+
## State ownership — choose one per slice
|
|
95
|
+
|
|
96
|
+
### Was: `writable` store + `onStateChange`
|
|
97
|
+
|
|
98
|
+
```svelte
|
|
99
|
+
<script lang="ts">
|
|
100
|
+
// v8
|
|
101
|
+
import { writable } from 'svelte/store'
|
|
102
|
+
const options = writable({ ... })
|
|
103
|
+
$: $options.state = $state
|
|
104
|
+
</script>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Now: pick one of three
|
|
108
|
+
|
|
109
|
+
**Internal (default).** Pass only `initialState` and let the table own it.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const table = createTable({
|
|
113
|
+
_features,
|
|
114
|
+
_rowModels: { paginatedRowModel: createPaginatedRowModel() },
|
|
115
|
+
columns,
|
|
116
|
+
get data() {
|
|
117
|
+
return data
|
|
118
|
+
},
|
|
119
|
+
initialState: {
|
|
120
|
+
pagination: { pageIndex: 0, pageSize: 25 },
|
|
121
|
+
},
|
|
122
|
+
})
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**External `state` + per-slice `on[State]Change`.** Closest to a literal v8 port.
|
|
126
|
+
|
|
127
|
+
```svelte
|
|
128
|
+
<script lang="ts">
|
|
129
|
+
let sorting: SortingState = $state([])
|
|
130
|
+
let pagination: PaginationState = $state({ pageIndex: 0, pageSize: 10 })
|
|
131
|
+
|
|
132
|
+
const table = createTable({
|
|
133
|
+
_features,
|
|
134
|
+
_rowModels: { ... },
|
|
135
|
+
columns,
|
|
136
|
+
get data() { return data },
|
|
137
|
+
state: {
|
|
138
|
+
get sorting() { return sorting },
|
|
139
|
+
get pagination() { return pagination },
|
|
140
|
+
},
|
|
141
|
+
onSortingChange: (updater) => {
|
|
142
|
+
sorting = updater instanceof Function ? updater(sorting) : updater
|
|
143
|
+
},
|
|
144
|
+
onPaginationChange: (updater) => {
|
|
145
|
+
pagination = updater instanceof Function ? updater(pagination) : updater
|
|
146
|
+
},
|
|
147
|
+
})
|
|
148
|
+
</script>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**External atoms (preferred for shared state).** Atomic, subscribable from anywhere.
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import { createAtom, useSelector } from '@tanstack/svelte-store'
|
|
155
|
+
|
|
156
|
+
const sortingAtom = createAtom<SortingState>([])
|
|
157
|
+
const paginationAtom = createAtom<PaginationState>({ pageIndex: 0, pageSize: 10 })
|
|
158
|
+
|
|
159
|
+
const sorting = useSelector(sortingAtom)
|
|
160
|
+
const pagination = useSelector(paginationAtom)
|
|
161
|
+
|
|
162
|
+
const table = createTable({
|
|
163
|
+
_features,
|
|
164
|
+
_rowModels: { ... },
|
|
165
|
+
columns,
|
|
166
|
+
get data() { return data },
|
|
167
|
+
atoms: {
|
|
168
|
+
sorting: sortingAtom,
|
|
169
|
+
pagination: paginationAtom,
|
|
170
|
+
},
|
|
171
|
+
})
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Do not combine** `state.pagination` with `atoms.pagination` — atoms always win, `state` is
|
|
175
|
+
discarded silently, you'll think your callbacks aren't firing.
|
|
176
|
+
|
|
177
|
+
## Rendering migration cheat sheet
|
|
178
|
+
|
|
179
|
+
```svelte
|
|
180
|
+
<!-- v8 -->
|
|
181
|
+
<th>
|
|
182
|
+
{#if !header.isPlaceholder}
|
|
183
|
+
<svelte:component
|
|
184
|
+
this={flexRender(header.column.columnDef.header, header.getContext())}
|
|
185
|
+
/>
|
|
186
|
+
{/if}
|
|
187
|
+
</th>
|
|
188
|
+
|
|
189
|
+
<!-- v9 -->
|
|
190
|
+
<th>
|
|
191
|
+
{#if !header.isPlaceholder}
|
|
192
|
+
<FlexRender {header} />
|
|
193
|
+
{/if}
|
|
194
|
+
</th>
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
For cells that render a custom Svelte component:
|
|
198
|
+
|
|
199
|
+
```svelte
|
|
200
|
+
<!-- v8: column def -->
|
|
201
|
+
{ cell: () => MyCellComponent }
|
|
202
|
+
|
|
203
|
+
<!-- v9: column def -->
|
|
204
|
+
import { renderComponent } from '@tanstack/svelte-table'
|
|
205
|
+
{ cell: ({ row }) => renderComponent(MyCellComponent, { row }) }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
For inline snippets:
|
|
209
|
+
|
|
210
|
+
```svelte
|
|
211
|
+
<!-- v9 -->
|
|
212
|
+
import { renderSnippet } from '@tanstack/svelte-table'
|
|
213
|
+
|
|
214
|
+
{#snippet myCell(row)}
|
|
215
|
+
<strong>{row.original.firstName}</strong>
|
|
216
|
+
{/snippet}
|
|
217
|
+
|
|
218
|
+
{ cell: ({ row }) => renderSnippet(myCell, row) }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## After the rewrite — verify
|
|
222
|
+
|
|
223
|
+
- `pnpm test:types` (or `svelte-check`) catches missing `<typeof _features, TData>` generics,
|
|
224
|
+
missing `_features` / `_rowModels`, and feature APIs called on tables that didn't register
|
|
225
|
+
them.
|
|
226
|
+
- `pnpm build` should pass with the new `_features` set. Bundle should shrink — only the
|
|
227
|
+
features you register are included.
|
|
228
|
+
- Click through every table screen. Reset buttons, multi-sort, pagination reset on filter,
|
|
229
|
+
expanded-row count under pagination — these are all the spots where v8 muscle memory
|
|
230
|
+
reaches for an option (`autoResetPageIndex` etc.) that's still named the same in v9 but
|
|
231
|
+
only takes effect if the matching feature is registered.
|
|
232
|
+
|
|
233
|
+
## Common failure modes during migration
|
|
234
|
+
|
|
235
|
+
- **Trying to skip the Svelte 5 upgrade.** Will not work.
|
|
236
|
+
- **Reaching for `useLegacyTable`.** Doesn't exist in `@tanstack/svelte-table`. That's a
|
|
237
|
+
React-only escape hatch.
|
|
238
|
+
- **Importing from `@tanstack/table-core` directly.** Re-exported by the adapter — go through
|
|
239
|
+
the adapter.
|
|
240
|
+
- **Plain `data` instead of `get data()` getter.** Largest single source of "but my data
|
|
241
|
+
changed" bugs during migration.
|
|
242
|
+
- **Plain `_features: { rowPaginationFeature }` instead of `tableFeatures({...})`.** Loses
|
|
243
|
+
inference; you'll get `any` everywhere.
|
|
244
|
+
- **Forgetting feature registration after copying the row-model factory.** Adding
|
|
245
|
+
`paginatedRowModel: createPaginatedRowModel()` without `rowPaginationFeature` in
|
|
246
|
+
`_features` does nothing.
|
|
247
|
+
- **Reimplementing v8 helpers** (`flexRender`-style functions, manual store subscriptions,
|
|
248
|
+
hand-rolled selectors) instead of using `FlexRender` / `subscribeTable` / atom selectors.
|
|
249
|
+
That's the #1 AI tell on this migration.
|
|
250
|
+
|
|
251
|
+
## Related skills
|
|
252
|
+
|
|
253
|
+
- `tanstack-table/svelte/getting-started` — clean-slate setup.
|
|
254
|
+
- `tanstack-table/svelte/table-state` — the v9 state model in depth.
|
|
255
|
+
- `tanstack-table/core/state-management` — atom precedence rules.
|
|
256
|
+
- `tanstack-table/svelte/production-readiness` — post-migration tuning.
|