Migrating from TanStack Table
TanStack Table (formerly React Table v8) is the closest conceptual
sibling to sv-grid - both are "headless data grid" libraries with
explicit row-model pipelines. If you already think in
createTable() + getCoreRowModel(), this is a half-day port.
Estimated effort: 30 min per grid for read-only views, 2-4 hours for editing-heavy grids.
On v9? SvGrid exports the same feature vocabulary, so most of this page is automated. Run
npx @svgrid/migrate srcto preview the port, and see Migrating from the shadcn-svelte data table if that is where your table came from.
Vocabulary cheat sheet
| TanStack Table | sv-grid |
|---|---|
useReactTable({...}) |
createSvGrid({...}) or <SvGrid> |
getCoreRowModel() |
createCoreRowModel() |
getSortedRowModel() |
Auto-registered by rowSortingFeature |
getFilteredRowModel() |
Auto-registered by columnFilteringFeature |
getPaginationRowModel() |
Built in; toggle with showPagination |
getGroupedRowModel() |
columnGroupingFeature + api.setGroupBy() |
getExpandedRowModel() |
rowExpandingFeature |
flexRender(col.cell, ctx) |
renderSnippet(MyCell, props) OR string field |
columnHelper.accessor('field') |
{ field: 'field' } directly |
table.getRowModel().rows |
api.getDisplayedRows() |
table.setColumnFilters(...) |
api.setFilter(id, {...}) per column |
meta (column / table) |
n/a - use column cellClass / cell instead |
Imports
The example at the end of this page runs against these rows:
<script lang="ts">
import { SvGrid, type GridColumns } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
{ id: 5, name: 'Barbara Liskov', department: 'Platform', city: 'Boston', age: 52, salary: 172000 },
]
let rows = $state<Person[]>(people)
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 200, editorType: 'text' },
{ field: 'department', header: 'Department', width: 150, editorType: 'text' },
{ field: 'city', header: 'City', width: 140, editorType: 'text' },
{ field: 'age', header: 'Age', width: 90, editorType: 'number' },
{ field: 'salary', header: 'Salary', width: 130, editorType: 'number', format: { type: 'currency', currency: 'USD' } },
]
</script>
- import {
- useReactTable, getCoreRowModel, getSortedRowModel, getFilteredRowModel,
- flexRender, createColumnHelper,
- } from '@tanstack/react-table'
+ import {
+ SvGrid, tableFeatures, rowSortingFeature, columnFilteringFeature,
+ renderSnippet,
+ } from '@svgrid/grid'
Column definitions
- const columnHelper = createColumnHelper<Order>()
- const columns = [
- columnHelper.accessor('orderId', { header: 'Order ID' }),
- columnHelper.accessor('amount', { header: 'Amount', cell: ({ getValue }) => fmt(getValue<number>()) }),
- ]
+ const columns: ColumnDef<typeof features, Order>[] = [
+ { field: 'orderId', header: 'Order ID' },
+ { field: 'amount', header: 'Amount', format: { type: 'currency', currency: 'USD' } },
+ ]
The fieldFn form is the same:
- columnHelper.accessor((row) => row.profile.name, { id: 'name', header: 'Name' })
+ { id: 'name', fieldFn: (row) => row.profile.name, header: 'Name' }
Mounting
- const table = useReactTable({
- data, columns,
- getCoreRowModel: getCoreRowModel(),
- getSortedRowModel: getSortedRowModel(),
- getFilteredRowModel: getFilteredRowModel(),
- })
- return (
- <table>
- <thead>{table.getHeaderGroups().map(/* ... */)}</thead>
- <tbody>{table.getRowModel().rows.map(/* ... */)}</tbody>
- </table>
- )
+ const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
+
+ <SvGrid data={rows} columns={columns} features={features} />
Sv-grid bundles the render + virtualization. No <table> you have
to author yourself.
Imperative state
| TanStack Table | sv-grid |
|---|---|
table.setColumnFilters([{id, value}]) |
api.setFilter(id, { operator: 'contains', value }) |
table.getColumn('id')?.setFilterValue(v) |
api.setFilter(id, { operator: 'contains', value: v }) |
table.setSorting([{id, desc}]) |
api.setSort(id, desc ? 'desc' : 'asc') |
table.setRowSelection(state) |
n/a - use api.clearRowSelection() + UI events |
table.toggleAllRowsExpanded() |
api.expandAllGroups() |
table.getColumn('x').toggleVisibility() |
api.setColumnVisible('x', false) |
table.options.meta?.foo |
Pass through component props / $state |
Custom cells
- {
- header: 'Status',
- cell: ({ row }) => <Badge tone={row.original.status} />,
- }
+ {
+ field: 'status', header: 'Status',
+ cell: (ctx) => renderSnippet(StatusCell, { tone: ctx.row.original.status }),
+ }
renderSnippet accepts any Svelte 5 snippet; renderComponent
accepts a regular component if you prefer SFCs.
Server-side data
- const [pagination, setPagination] = useState({pageIndex: 0, pageSize: 25})
- const [sorting, setSorting] = useState([])
- const table = useReactTable({
- data, columns, manualPagination: true, manualSorting: true,
- state: { pagination, sorting },
- onPaginationChange: setPagination,
- onSortingChange: setSorting,
- })
+ <SvGrid
+ data={rows} columns={columns} features={features}
+ externalSort={true}
+ externalFilter={true}
+ onSortingChange={(clauses) => refetch({ sort: clauses })}
+ onFiltersChange={(f) => refetch({ filters: f.columns })}
+ />
What you get for free vs TanStack Table
- Renderer. TanStack is headless-only; you draw the
<table>. Sv-grid ships an opinionated, fast renderer with virtualization, scroll, sticky headers, column resize, keyboard nav, ARIA. - Inline editing.
editorType: 'text' | 'number' | 'date' | 'list' | ...- built-in editors with parsing + validation hooks. - CSP-clean. No
eval. The shipped tests confirm. - Enterprise features. Export, import, pivot, AI - in one paid add-on.
What you give up
- React-first ecosystem. Sv-grid is Svelte 5-native. There's no React wrapper.
metafor arbitrary side-channel state. Pass props directly.@tanstack/match-sorter-utilsintegration. The grid's filter has acontainsoperator; if you need fuzzy match, plug your matcher in via the column'scellsnippet or useexternalFilter={true}and run the matcher yourself.
Frequently asked questions
How long does it take to migrate from TanStack Table to SvGrid?
About 30 minutes per read-only grid and 2-4 hours for editing-heavy grids.
Both libraries use explicit row-model pipelines, so createTable() +
getCoreRowModel() maps almost directly onto createSvGrid() +
createCoreRowModel().
Why switch from TanStack Table to SvGrid on Svelte 5?
TanStack Table is headless-only and multi-framework, so you build the entire
DOM, virtualization, filter UI, and editing layer yourself. SvGrid keeps the
headless core but ships a batteries-included <SvGrid> render component -
virtualization, Excel-style filters, cell selection, and inline editing work
in one prop pass.
Is SvGrid free like TanStack Table?
Yes - @svgrid/grid is MIT-licensed, like TanStack Table. SvGrid
additionally offers an optional paid @svgrid/enterprise pack for export, pivot, and
import, which TanStack Table does not provide at all.
What you end up with
The same model you had, with the rendering already written.
<SvGrid data={rows} {columns} sortable filterable pageable pageSize={3} selectable />
See also
- Architecture - the headless engine + render component split
- Migrating from AG Grid - sibling guide
- Why headless? - the design rationale
Related articles
- Migrating a Svelte 4 Table Component to Svelte 5 - A concept-by-concept guide to porting a hand-rolled Svelte 4 data table to Svelte 5 runes - props, reactivity, stores, slots, events, and when to stop hand-rolling entirely.
- Migrating from DataTables.net to a Svelte Data Grid - A practical migration guide from jQuery DataTables to SvGrid - how column definitions, server-side data, custom rendering, and selection map across, with working code for each step.
- Migrating from ag-grid-react to a Svelte Stack - A practical field guide for porting ag-grid-react screens to SvGrid - column defs, cell renderers, server-side data, and the React-to-Svelte reactivity shift.