Use Svelte 5 rune-aware table atoms and stores, $derived projections, reactive option getters, controlled $state or createTableState slices, external atoms, and auto-reset behavior without broad invalidation or snapshot mismatches.
60
71%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./packages/svelte-table/skills/table-state/SKILL.mdThis skill builds on @tanstack/table-core#core and getting-started. Read them first for table ownership and Svelte construction.
TanStack Table is primarily a state coordinator. Keep state internal unless another system must read, persist, or drive it. Without initialState, atoms, state, or on[State]Change, the table owns all registered slices.
table.baseAtoms are internal writable atoms initialized from resolved initial state.table.atoms are readonly derived atoms for the active owner of each registered slice.table.store is the readonly flat store assembled from those atoms.The Svelte adapter bridges TanStack Store dependency tracking into Svelte runes. table.atoms.<slice>.get(), table.store.get(), and table APIs become reactive when called in a template, $derived, $derived.by, or $effect. Outside those contexts they return current snapshots.
Only registered features create state and types. If pagination is missing, register rowPaginationFeature; do not add a cast or ad hoc state field. Keep features and columns stable and pass changing data through a getter.
Keep state internal unless another subsystem needs to own it. Read only the state slices a component needs.
<script lang="ts">
import {
createTable,
rowPaginationFeature,
tableFeatures,
} from '@tanstack/svelte-table'
const features = tableFeatures({ rowPaginationFeature })
const columns = [{ accessorKey: 'name' }]
let data = $state([{ name: 'Ada' }])
const table = createTable({
features,
columns,
get data() {
return data
},
})
const pagination = $derived(table.atoms.pagination.get())
</script>
<button onclick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
Page {pagination.pageIndex + 1}
</button>const pagination = $derived(table.atoms.pagination.get())
const pageIndex = $derived(table.atoms.pagination.get().pageIndex)
const rows = $derived(table.getRowModel().rows)
const stateJson = $derived(JSON.stringify(table.store.get(), null, 2))Use atom reads for normal UI. A table.store.get() read intentionally re-runs for any registered state change, so reserve it for debug output, persistence, or computations that need the whole state.
import type { PaginationState, Updater } from '@tanstack/svelte-table'
let pagination = $state<PaginationState>({ pageIndex: 0, pageSize: 20 })
const updatePagination = (next: Updater<PaginationState>) => {
pagination = typeof next === 'function' ? next(pagination) : next
}Pass a getter-backed state.pagination and onPaginationChange: updatePagination to createTable.
createTableStateimport {
createTable,
createTableState,
rowPaginationFeature,
tableFeatures,
type PaginationState,
} from '@tanstack/svelte-table'
const features = tableFeatures({ rowPaginationFeature })
const columns = [{ accessorKey: 'name' }]
const data = [{ name: 'Ada' }]
const [pagination, setPagination] = createTableState<PaginationState>({
pageIndex: 0,
pageSize: 20,
})
const table = createTable({
features,
columns,
data,
state: {
get pagination() {
return pagination()
},
},
onPaginationChange: setPagination,
})For better or worse, this resembles a small React useState hook: pagination() reads the current rune-backed value, while setPagination accepts either a value or a functional updater and can be passed directly to onPaginationChange.
Use one owner per slice:
initialState for starting/reset values; changing it later does not reset state.$state, a getter-backed state entry, and the matching callback for normal Svelte-owned controlled state.atoms for state shared as a raw TanStack Store atom. Do not also add its change callback.External atoms win over controlled state, which syncs into the internal base atom. Avoid multiple owners. The global v8 onStateChange option is gone; subscribe to table.store if every state change must be observed imperatively.
When code outside the table consumes a raw external atom, use useSelector from @tanstack/svelte-store. Inside table-driven UI, read the rune-aware table.atoms.<slice>.get() wrapper.
Prefer setSorting, nextPage, toggleVisibility, toggleSelected, and other feature APIs over direct state writes. Write a base atom only for rare internal-state needs; write the external atom when atoms.<slice> owns it.
table.resetSorting()
table.resetPagination()
table.resetPagination(true)Feature resets use table.initialState unless true requests the feature default and can flow to external owners. Core table.reset() resets internal base atoms only. Use feature types such as PaginationState for a slice and TableState<typeof features> for the complete registered state.
Wrong:
const table = createTable(options, (state) => state.pagination)
const pageIndex = table.state.pageIndexCorrect:
const table = createTable(options)
const pagination = $derived(table.atoms.pagination.get())Starting in beta.59, createTable and createAppTable take only options, table.state is absent, and subscribeTable and SubscribeSource are no longer exported. Use native tracked Svelte reads and $derived projections.
Source: docs/framework/svelte/guide/migrating.md
Wrong:
const options = { state: { pagination }, onPaginationChange: console.log }Correct:
const options = {
state: {
get pagination() {
return pagination
},
},
onPaginationChange: updatePagination,
}A controlled slice is frozen unless every updater is resolved into the owning rune.
Source: docs/framework/svelte/guide/table-state.md
Wrong:
const pageIndex = table.store.get().pagination.pageIndexCorrect inside a component:
const pageIndex = $derived(table.atoms.pagination.get().pageIndex)The first line is only a current snapshot when it runs outside a template or rune. The second line is a narrow native Svelte derivation.
Source: packages/svelte-table/src/createTable.svelte.ts
Wrong:
const options = { initialState: { pagination: start }, state: { pagination } }Correct:
const options = {
state: {
get pagination() {
return pagination
},
},
}Controlled atoms or state wins over initialState; choose one owner per slice.
Source: docs/framework/svelte/guide/table-state.md
Wrong:
table.setPageIndex(4)
data = filteredDataCorrect:
const options = { autoResetPageIndex: false }Client row-model changes reset the page by default; disable it only when the application handles invalid empty pages.
Source: docs/framework/svelte/guide/pagination.md
Inspect node_modules/@tanstack/svelte-table/dist/createTable.svelte.d.ts, createTableHook.svelte.d.ts, and createTableState.svelte.d.ts; inspect registered state slices in the matching core feature source.
9e523bc
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.