@tanstack/svelte-table 9.0.0-beta.7 → 9.0.0-beta.71

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 (48) hide show
  1. package/README.md +5 -1
  2. package/dist/FlexRender.svelte +15 -1
  3. package/dist/createTable.svelte.d.ts +26 -36
  4. package/dist/createTable.svelte.js +27 -32
  5. package/dist/createTableHook.svelte.d.ts +51 -18
  6. package/dist/createTableHook.svelte.js +18 -10
  7. package/dist/experimental-worker-plugin.d.ts +1 -0
  8. package/dist/experimental-worker-plugin.js +1 -0
  9. package/dist/index.d.ts +1 -2
  10. package/dist/index.js +0 -1
  11. package/dist/reactivity.svelte.d.ts +3 -1
  12. package/dist/reactivity.svelte.js +6 -1
  13. package/dist/render-component.js +4 -0
  14. package/package.json +16 -9
  15. package/skills/create-table-hook/SKILL.md +168 -0
  16. package/skills/getting-started/SKILL.md +172 -0
  17. package/skills/migrate-v8-to-v9/SKILL.md +201 -0
  18. package/skills/table-state/SKILL.md +262 -0
  19. package/skills/with-tanstack-query/SKILL.md +149 -0
  20. package/skills/with-tanstack-virtual/SKILL.md +150 -0
  21. package/dist/subscribe.d.ts +0 -24
  22. package/dist/subscribe.js +0 -4
  23. package/skills/svelte/client-to-server/SKILL.md +0 -238
  24. package/skills/svelte/compose-with-tanstack-form/SKILL.md +0 -295
  25. package/skills/svelte/compose-with-tanstack-pacer/SKILL.md +0 -176
  26. package/skills/svelte/compose-with-tanstack-query/SKILL.md +0 -299
  27. package/skills/svelte/compose-with-tanstack-store/SKILL.md +0 -277
  28. package/skills/svelte/compose-with-tanstack-virtual/SKILL.md +0 -286
  29. package/skills/svelte/getting-started/SKILL.md +0 -340
  30. package/skills/svelte/migrate-v8-to-v9/SKILL.md +0 -256
  31. package/skills/svelte/production-readiness/SKILL.md +0 -256
  32. package/skills/svelte/table-state/SKILL.md +0 -441
  33. package/src/AppCell.svelte +0 -13
  34. package/src/AppHeader.svelte +0 -13
  35. package/src/AppTable.svelte +0 -11
  36. package/src/FlexRender.svelte +0 -103
  37. package/src/context-keys.ts +0 -3
  38. package/src/createTable.svelte.ts +0 -137
  39. package/src/createTableHook.svelte.ts +0 -639
  40. package/src/createTableState.svelte.ts +0 -30
  41. package/src/flex-render.ts +0 -3
  42. package/src/global.d.ts +0 -1
  43. package/src/index.ts +0 -21
  44. package/src/merge-objects.ts +0 -79
  45. package/src/reactivity.svelte.ts +0 -118
  46. package/src/render-component.ts +0 -107
  47. package/src/static-functions.ts +0 -1
  48. package/src/subscribe.ts +0 -46
@@ -1,441 +0,0 @@
1
- ---
2
- name: svelte/table-state
3
- description: >
4
- Svelte 5 rune-based reactivity for TanStack Table v9. Covers `createTable(options, selector?)`,
5
- the `table.state` selector projection, fine-grained `subscribeTable(atom, selector?)` with `.current`,
6
- reading and writing `table.atoms` / `table.baseAtoms`, the `svelteReactivity()` bridge that backs
7
- readonly atoms with `$derived.by` and writable atoms with `$state`, and the `$effect.pre` option
8
- sync. State ownership: `initialState`, `state` + `on[State]Change`, or external `atoms` from
9
- `@tanstack/svelte-store` (`createAtom`, `useSelector`). Svelte 5+ only — no Svelte 3/4 support.
10
- type: framework
11
- library: tanstack-table
12
- framework: svelte
13
- library_version: '9.0.0-alpha.48'
14
- requires:
15
- - state-management
16
- - setup
17
- sources:
18
- - TanStack/table:docs/framework/svelte/svelte-table.md
19
- - TanStack/table:docs/framework/svelte/guide/table-state.md
20
- - TanStack/table:packages/svelte-table/src/createTable.svelte.ts
21
- - TanStack/table:packages/svelte-table/src/createTableHook.svelte.ts
22
- - TanStack/table:packages/svelte-table/src/reactivity.svelte.ts
23
- - TanStack/table:packages/svelte-table/src/subscribe.ts
24
- - TanStack/table:examples/svelte/basic-create-table/
25
- - TanStack/table:examples/svelte/basic-external-atoms/
26
- - TanStack/table:examples/svelte/basic-external-state/
27
- ---
28
-
29
- # Svelte Table State, `subscribeTable` & `createTableHook`
30
-
31
- > **TanStack Table is a state-management coordinator for table state.** Understanding how state
32
- > flows through atoms, runes, and selectors is foundational to everything else you do with the
33
- > Svelte adapter.
34
-
35
- ## Critical: Svelte 5+ only
36
-
37
- `@tanstack/svelte-table@9` requires **Svelte 5 or newer**. The adapter is built on runes
38
- (`$state`, `$derived.by`, `$effect.pre`). For Svelte 3/4 projects, stay on
39
- `@tanstack/svelte-table@8` — there is no v9 path that supports the legacy stores API.
40
-
41
- ## How v9 state is wired in Svelte
42
-
43
- A table instance has three (and a half) state surfaces:
44
-
45
- - `table.baseAtoms.<slice>` — writable atoms created from the resolved initial state.
46
- - `table.atoms.<slice>` — readonly derived atoms, exposed per registered feature.
47
- - `table.store` — readonly flat TanStack Store, a derived view of all registered atoms.
48
- - `table.state` — the value returned by the optional selector passed as the second argument to
49
- `createTable`. **Svelte-only surface.**
50
-
51
- The Svelte adapter installs `svelteReactivity()` as the `coreReativityFeature`:
52
-
53
- | Core concept | Svelte binding |
54
- | ------------- | --------------- |
55
- | readonly atom | `$derived.by()` |
56
- | writable atom | `$state` |
57
- | subscription | rune `$effect` |
58
- | option sync | `$effect.pre` |
59
- | batch | `flushSync` |
60
-
61
- `createTable` reads reactive option getters inside `$effect.pre` so the table sees fresh data,
62
- columns, and controlled state **before** the DOM renders — `getRowModel()` is never a frame behind.
63
-
64
- ## Feature-based state — registered features only
65
-
66
- State slices only exist for the features registered in `features`. Reading
67
- `table.atoms.rowSelection` without `rowSelectionFeature` is a TypeScript error and a runtime
68
- `undefined`. **This is the most common v9 mistake.**
69
-
70
- ```ts
71
- import {
72
- createTable,
73
- rowPaginationFeature,
74
- rowSortingFeature,
75
- tableFeatures,
76
- createPaginatedRowModel,
77
- createSortedRowModel,
78
- sortFns,
79
- } from '@tanstack/svelte-table'
80
-
81
- const features = tableFeatures({
82
- rowPaginationFeature,
83
- rowSortingFeature,
84
- })
85
-
86
- const table = createTable({
87
- features,
88
- rowModels: {
89
- paginatedRowModel: createPaginatedRowModel(),
90
- sortedRowModel: createSortedRowModel(sortFns),
91
- },
92
- columns,
93
- get data() {
94
- return data
95
- },
96
- })
97
-
98
- table.atoms.pagination.get() // ok
99
- table.atoms.sorting.get() // ok
100
- // table.atoms.rowSelection // TypeScript error
101
- ```
102
-
103
- ## Reading state — pick the right tool for the job
104
-
105
- ### Current value, no reactivity
106
-
107
- Read the atom directly. Cheapest path; only reactive when called inside a rune-tracked context.
108
-
109
- ```ts
110
- const sorting = table.atoms.sorting.get()
111
- const pagination = table.atoms.pagination.get()
112
- const flat = table.state
113
- ```
114
-
115
- ### Reactive read inside markup — `table.state` selector
116
-
117
- Pass a TanStack Store selector as the second argument to `createTable`. The selected value is
118
- exposed as `table.state`. The default selector returns the full registered state.
119
-
120
- ```svelte
121
- <script lang="ts">
122
- const table = createTable(
123
- {
124
- features,
125
- rowModels: { paginatedRowModel: createPaginatedRowModel() },
126
- columns,
127
- get data() {
128
- return data
129
- },
130
- },
131
- (state) => ({ pagination: state.pagination }),
132
- )
133
- </script>
134
-
135
- <strong>
136
- Page {table.state.pagination.pageIndex + 1} of {table.getPageCount()}
137
- </strong>
138
- ```
139
-
140
- ### Fine-grained — `subscribeTable`
141
-
142
- `subscribeTable(source, selector?)` wraps a `useSelector` with `shallow` compare and returns an
143
- object whose `.current` is the selected value. Use it when only one block of markup should
144
- re-render on a state change.
145
-
146
- ```ts
147
- import { subscribeTable } from '@tanstack/svelte-table'
148
-
149
- const pageIndex = subscribeTable(table.atoms.pagination, (p) => p.pageIndex)
150
- ```
151
-
152
- ```svelte
153
- <strong>Page {pageIndex.current + 1}</strong>
154
- ```
155
-
156
- ## Setting state — APIs first, atoms last
157
-
158
- Use the feature APIs. They handle updaters, external-atom routing, and validation:
159
-
160
- ```ts
161
- table.nextPage()
162
- table.previousPage()
163
- table.setPageIndex(0)
164
- table.setPageSize(25)
165
- table.setSorting([{ id: 'age', desc: true }])
166
- column.toggleVisibility()
167
- row.toggleSelected()
168
- ```
169
-
170
- Direct base-atom writes are a last resort:
171
-
172
- ```ts
173
- table.baseAtoms.pagination.set((old) => ({ ...old, pageIndex: 0 }))
174
- ```
175
-
176
- When a slice is owned by an external atom (passed through `atoms`), write to the external atom —
177
- `table.atoms.<slice>` will read from it, not from `baseAtoms`.
178
-
179
- ## State ownership — three patterns
180
-
181
- ### 1. Initial state only
182
-
183
- The default: set starting values, let the table own the rest. `initialState` also drives
184
- `resetSorting()`, `resetPagination()`, etc.
185
-
186
- ```ts
187
- const table = createTable({
188
- features,
189
- rowModels: {},
190
- columns,
191
- get data() {
192
- return data
193
- },
194
- initialState: {
195
- sorting: [{ id: 'age', desc: true }],
196
- pagination: { pageIndex: 0, pageSize: 25 },
197
- },
198
- })
199
- ```
200
-
201
- ### 2. External atoms (recommended for shared state)
202
-
203
- When the app should own a slice, create a stable atom with `createAtom`, pass it through `atoms`,
204
- and subscribe with `useSelector` or `subscribeTable`. The table writes through the external atom
205
- on `setPageIndex`, `setSorting`, etc.
206
-
207
- ```ts
208
- import { createAtom, useSelector } from '@tanstack/svelte-store'
209
- import {
210
- createTable,
211
- rowPaginationFeature,
212
- rowSortingFeature,
213
- tableFeatures,
214
- type PaginationState,
215
- type SortingState,
216
- } from '@tanstack/svelte-table'
217
-
218
- const features = tableFeatures({
219
- rowPaginationFeature,
220
- rowSortingFeature,
221
- })
222
-
223
- const sortingAtom = createAtom<SortingState>([])
224
- const paginationAtom = createAtom<PaginationState>({
225
- pageIndex: 0,
226
- pageSize: 10,
227
- })
228
-
229
- const sorting = useSelector(sortingAtom)
230
- const pagination = useSelector(paginationAtom)
231
-
232
- const table = createTable({
233
- features,
234
- rowModels: {},
235
- columns,
236
- get data() {
237
- return data
238
- },
239
- atoms: {
240
- sorting: sortingAtom,
241
- pagination: paginationAtom,
242
- },
243
- })
244
- ```
245
-
246
- When you use `atoms` for a slice, **do not** pair it with the matching `on[State]Change` callback.
247
-
248
- ### 3. External `state` + `on[State]Change` (migration / simple cases)
249
-
250
- Classic pattern, still supported. Use Svelte 5 `$state` and getter properties so the table sees
251
- updates.
252
-
253
- ```svelte
254
- <script lang="ts">
255
- import {
256
- createTable,
257
- rowPaginationFeature,
258
- rowSortingFeature,
259
- tableFeatures,
260
- type PaginationState,
261
- type SortingState,
262
- } from '@tanstack/svelte-table'
263
-
264
- let sorting: SortingState = $state([])
265
- let pagination: PaginationState = $state({ pageIndex: 0, pageSize: 10 })
266
-
267
- const table = createTable({
268
- features,
269
- rowModels: {},
270
- columns,
271
- get data() {
272
- return data
273
- },
274
- state: {
275
- get sorting() {
276
- return sorting
277
- },
278
- get pagination() {
279
- return pagination
280
- },
281
- },
282
- onSortingChange: (updater) => {
283
- sorting = updater instanceof Function ? updater(sorting) : updater
284
- },
285
- onPaginationChange: (updater) => {
286
- pagination = updater instanceof Function ? updater(pagination) : updater
287
- },
288
- })
289
- </script>
290
- ```
291
-
292
- > The v8-style monolithic `onStateChange` is gone in v9. Use per-slice `on[State]Change` or, better,
293
- > external atoms.
294
-
295
- ### Precedence — do not mix sources
296
-
297
- External `atoms` win over external `state`. External `state` syncs into the internal base atom.
298
- For any given slice, pick **one** source of truth. Don't pass `initialState.pagination` and
299
- `atoms.pagination` and `state.pagination` together.
300
-
301
- ## Rendering — `FlexRender`
302
-
303
- `FlexRender` handles `header`, `cell`, and `footer` definitions whether they're plain strings,
304
- Svelte components wrapped with `renderComponent`, or snippets wrapped with `renderSnippet`.
305
-
306
- ```svelte
307
- <script lang="ts">
308
- import {
309
- FlexRender,
310
- renderComponent,
311
- renderSnippet,
312
- } from '@tanstack/svelte-table'
313
- </script>
314
-
315
- <thead>
316
- {#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
317
- <tr>
318
- {#each headerGroup.headers as header (header.id)}
319
- <th>
320
- {#if !header.isPlaceholder}
321
- <FlexRender {header} />
322
- {/if}
323
- </th>
324
- {/each}
325
- </tr>
326
- {/each}
327
- </thead>
328
- <tbody>
329
- {#each table.getRowModel().rows as row (row.id)}
330
- <tr>
331
- {#each row.getVisibleCells() as cell (cell.id)}
332
- <td><FlexRender {cell} /></td>
333
- {/each}
334
- </tr>
335
- {/each}
336
- </tbody>
337
- ```
338
-
339
- Always key `{#each}` blocks on stable ids (`headerGroup.id`, `header.id`, `row.id`, `cell.id`).
340
-
341
- ## `createTableHook` — app-wide composition
342
-
343
- Create one configured hook per app: shared `features`, `rowModels`, defaults, and pre-bound
344
- component registries.
345
-
346
- ```ts
347
- import {
348
- createPaginatedRowModel,
349
- createSortedRowModel,
350
- createTableHook,
351
- rowPaginationFeature,
352
- rowSortingFeature,
353
- sortFns,
354
- tableFeatures,
355
- } from '@tanstack/svelte-table'
356
- import TextCell from './cells/TextCell.svelte'
357
- import SortIndicator from './headers/SortIndicator.svelte'
358
-
359
- export const {
360
- createAppTable,
361
- createAppColumnHelper,
362
- useTableContext,
363
- useCellContext,
364
- useHeaderContext,
365
- } = createTableHook({
366
- features: tableFeatures({ rowPaginationFeature, rowSortingFeature }),
367
- rowModels: {
368
- paginatedRowModel: createPaginatedRowModel(),
369
- sortedRowModel: createSortedRowModel(sortFns),
370
- },
371
- cellComponents: { TextCell },
372
- headerComponents: { SortIndicator },
373
- })
374
- ```
375
-
376
- In components:
377
-
378
- ```svelte
379
- <script lang="ts">
380
- import { createAppTable, createAppColumnHelper } from './hooks/table'
381
-
382
- const columnHelper = createAppColumnHelper<Person>()
383
- const columns = columnHelper.columns([
384
- columnHelper.accessor('firstName', { header: 'First' }),
385
- ])
386
-
387
- const table = createAppTable({
388
- columns,
389
- get data() {
390
- return data
391
- },
392
- })
393
- </script>
394
-
395
- <table.AppTable>
396
- {#snippet children()}
397
- <table>
398
- <thead>
399
- {#each table.getHeaderGroups() as group (group.id)}
400
- <tr>
401
- {#each group.headers as header (header.id)}
402
- <table.AppHeader {header}>
403
- {#snippet children(h)}
404
- <th><h.SortIndicator /></th>
405
- {/snippet}
406
- </table.AppHeader>
407
- {/each}
408
- </tr>
409
- {/each}
410
- </thead>
411
- </table>
412
- {/snippet}
413
- </table.AppTable>
414
- ```
415
-
416
- Inside custom `cellComponents` / `headerComponents` / `tableComponents`, use `useCellContext()` /
417
- `useHeaderContext()` / `useTableContext()` instead of prop-drilling.
418
-
419
- ## Common failure modes
420
-
421
- - **Svelte 4 code with v9 adapter.** Will not run. `$state` / `$derived.by` are Svelte 5 syntax.
422
- - **`createSvelteTable` import.** v8 name. v9 uses `createTable`. There is no `useSvelteTable`,
423
- `getCoreRowModel`, `getSortedRowModel`, etc. — those are v8 names too.
424
- - **Forgetting `tableFeatures()`.** `features` must come from `tableFeatures({...})` for type
425
- inference; passing a raw object loses the typed state slice keys.
426
- - **Forgetting feature registration.** Calling `table.setSorting(...)` without
427
- `rowSortingFeature` in `features` is a runtime no-op (the API method won't exist).
428
- - **Mixing ownership.** `atoms.pagination` + `state.pagination` + `initialState.pagination` is
429
- ambiguous; the table will not "merge" them the way you expect.
430
- - **Reactive getters dropped.** If you pass `data` as a plain value instead of a getter, the
431
- table won't re-render when `data` changes. Always use `get data() { return data }`.
432
- - **Reimplementing built-ins.** If you're hand-rolling sorting comparators, pagination math, or
433
- selection toggles, you're skipping `rowSortingFeature` / `rowPaginationFeature` /
434
- `rowSelectionFeature` and their reset / state APIs. Register the feature instead.
435
-
436
- ## Related skills
437
-
438
- - `tanstack-table/core/state-management` — atom model, slice precedence, base vs derived atoms.
439
- - `tanstack-table/svelte/getting-started` — end-to-end first table.
440
- - `tanstack-table/svelte/compose-with-tanstack-store` — direct atom interop.
441
- - `tanstack-table/svelte/production-readiness` — selector / subscription tuning.
@@ -1,13 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte'
3
-
4
- interface Props {
5
- cell: any
6
- cellComponents: any
7
- children: Snippet<[any]>
8
- }
9
-
10
- let { children, cell, cellComponents }: Props = $props()
11
- </script>
12
-
13
- {@render children?.(Object.assign(cell, cellComponents))}
@@ -1,13 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte'
3
-
4
- interface Props {
5
- header: any
6
- headerComponents: any
7
- children: Snippet<[any]>
8
- }
9
-
10
- let { children, header, headerComponents }: Props = $props()
11
- </script>
12
-
13
- {@render children?.(Object.assign(header, headerComponents))}
@@ -1,11 +0,0 @@
1
- <script lang="ts">
2
- import type { Snippet } from 'svelte'
3
-
4
- interface Props {
5
- children: Snippet
6
- }
7
-
8
- let { children }: Props = $props()
9
- </script>
10
-
11
- {@render children?.()}
@@ -1,103 +0,0 @@
1
- <script
2
- lang="ts"
3
- generics="TFeatures extends TableFeatures, TData extends RowData, TValue extends CellData"
4
- >
5
- import { isFunction } from '@tanstack/table-core'
6
- import {
7
- RenderComponentConfig,
8
- RenderSnippetConfig,
9
- } from './render-component'
10
- import type {
11
- Cell,
12
- CellContext,
13
- CellData,
14
- ColumnDefTemplate,
15
- Header,
16
- HeaderContext,
17
- RowData,
18
- TableFeatures,
19
- } from '@tanstack/table-core'
20
-
21
- type Props =
22
- | {
23
- /** The cell or header field of the current cell's column definition. */
24
- content?: ColumnDefTemplate<
25
- | HeaderContext<TFeatures, TData, TValue>
26
- | CellContext<TFeatures, TData, TValue>
27
- >
28
- /** The result of the `getContext()` function of the header or cell */
29
- context:
30
- | HeaderContext<TFeatures, TData, TValue>
31
- | CellContext<TFeatures, TData, TValue>
32
- cell?: never
33
- header?: never
34
- footer?: never
35
- }
36
- | {
37
- cell: Cell<TFeatures, TData, TValue>
38
- content?: never
39
- context?: never
40
- header?: never
41
- footer?: never
42
- }
43
- | {
44
- header: Header<TFeatures, TData, TValue>
45
- content?: never
46
- context?: never
47
- cell?: never
48
- footer?: never
49
- }
50
- | {
51
- footer: Header<TFeatures, TData, TValue>
52
- content?: never
53
- context?: never
54
- cell?: never
55
- header?: never
56
- }
57
-
58
- let props: Props = $props()
59
-
60
- // Resolve content and context from either the new cell/header/footer props
61
- // or the legacy content/context props.
62
- const resolved = $derived.by(() => {
63
- if ('cell' in props && props.cell) {
64
- return {
65
- content: props.cell.column.columnDef.cell,
66
- context: props.cell.getContext(),
67
- }
68
- }
69
- if ('header' in props && props.header) {
70
- return {
71
- content: props.header.column.columnDef.header,
72
- context: props.header.getContext(),
73
- }
74
- }
75
- if ('footer' in props && props.footer) {
76
- return {
77
- content: props.footer.column.columnDef.footer,
78
- context: props.footer.getContext(),
79
- }
80
- }
81
- return {
82
- content: props.content,
83
- context: props.context,
84
- }
85
- })
86
-
87
- // Compute the render result reactively
88
- const result = $derived(
89
- isFunction(resolved.content)
90
- ? resolved.content(resolved.context as any)
91
- : undefined,
92
- )
93
- </script>
94
-
95
- {#if typeof resolved.content === 'string'}
96
- {resolved.content}
97
- {:else if result instanceof RenderComponentConfig}
98
- <result.component {...result.props} />
99
- {:else if result instanceof RenderSnippetConfig}
100
- {@render result.snippet(result.params)}
101
- {:else if result !== undefined}
102
- {result}
103
- {/if}
@@ -1,3 +0,0 @@
1
- export const tableContextKey = '__tanstack_table_context_key'
2
- export const cellContextKey = '__tanstack_cell_context_key'
3
- export const headerContextKey = '__tanstack_header_context_key'