<!-- https://svgrid.com/docs/help/migrating-from-ui-kit-tables/ - SvGrid documentation as markdown. Index of every page: https://svgrid.com/llms.txt -->

# Migrating from a UI-kit table (Flowbite / Skeleton / shadcn-svelte)

Flowbite-Svelte, Skeleton, and shadcn-svelte all ship a styled `<Table>`
component. They are presentation components: they render the rows you
pass and match your design tokens, but sorting, filtering,
virtualization, and editing are yours to write by hand. Moving to SvGrid
replaces that hand-rolled logic with built-in features - while still
letting you match the design system.

> **Not the shadcn-svelte data table.** That one is a separate recipe
> built on TanStack Table v9, and it already does sorting, filtering,
> pagination, and row selection. If that is what you have, read
> [Migrating from the shadcn-svelte data table](https://svgrid.com/docs/help/migrating-from-shadcn-data-table/)
> instead - the port is different, and smaller.

<!-- facts:start svelte-ui-kit-tables -->
> **Facts, checked 12 Sep 2026.** `@svgrid/grid` 3.0.3, MIT, last published 11 Sep 2026, 16,900 npm downloads in the 30 days to 10 Sep 2026. Bundle, minified and gzipped, each package built alone with Svelte external: SvGrid 3.0.28 99.7 KB JS + 11.3 KB CSS (measured 29 Oct 2026). Flowbite / Skeleton / shadcn-svelte tables pricing, as its site states it: Flowbite Svelte, Skeleton and shadcn-svelte are MIT component libraries; their table components are free and no grid licence is sold (https://github.com/themesberg/flowbite-svelte, read 12 Sep 2026). SvGrid: MIT core; @svgrid/enterprise from $299 per developer per year (Indie, under $1M revenue), $599 for Enterprise. Side by side, with sources: [SvGrid vs Flowbite / Skeleton / shadcn-svelte tables](https://svgrid.com/compare/svelte-ui-kit-tables/).
<!-- facts:end -->

> Estimated effort: **30 min - 1 hour** per table. You are mostly
> deleting `{#each}` markup and the sort / filter state you wrote
> yourself.

## When this guide applies

You have a table that started simple and has grown:

- You added a click-to-sort handler and a sort-state variable.
- You added a search box and an array `.filter(...)`.
- The list got long and now you want virtualization or pagination.
- You started editing cells inline and it got messy.

That is the moment a styled `<Table>` stops paying for itself.

## Before / after

The example at the end of this page runs against these rows:

```svelte
<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>
```

```diff
- <script>
-   import { Table, TableHead, TableHeadCell, TableBody, TableBodyRow, TableBodyCell } from 'flowbite-svelte'
-   let sortKey = 'name', asc = true
-   $: sorted = [...rows].sort((a, b) => (a[sortKey] > b[sortKey] ? 1 : -1) * (asc ? 1 : -1))
- </script>
-
- <Table>
-   <TableHead>
-     <TableHeadCell on:click={() => (sortKey = 'name')}>Name</TableHeadCell>
-     <TableHeadCell on:click={() => (sortKey = 'amount')}>Amount</TableHeadCell>
-   </TableHead>
-   <TableBody>
-     {#each sorted as row}
-       <TableBodyRow>
-         <TableBodyCell>{row.name}</TableBodyCell>
-         <TableBodyCell>{row.amount}</TableBodyCell>
-       </TableBodyRow>
-     {/each}
-   </TableBody>
- </Table>

+ <script lang="ts">
+   import {
+     SvGrid, tableFeatures, rowSortingFeature, columnFilteringFeature,
+     type ColumnDef,
+   } from '@svgrid/grid'
+
+   const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
+   const columns: ColumnDef<typeof features, Row>[] = [
+     { field: 'name',   header: 'Name' },
+     { field: 'amount', header: 'Amount', format: { type: 'currency', currency: 'USD' } },
+   ]
+ </script>
+
+ <SvGrid data={rows} columns={columns} features={features} showPagination />
```

The sort handler, the `sorted` derivation, and the `{#each}` all go
away. Sorting is a click on the header; filtering is the column menu.

## Keep your design system

SvGrid is unstyled-by-token, so it can match Flowbite / Skeleton /
shadcn:

- Re-theme through the `--sg-*` CSS custom properties (borders, header
  background, zebra rows, hover, selection, density).
- Or drive those tokens from your Tailwind theme - see the
  [Tailwind integration](https://svgrid.com/docs/help/tailwind/) guide.

## What you get for free

- **Sorting, filtering, and pagination** without writing handlers.
- **Row + column virtualization** so thousands of rows stay smooth.
- **Inline editing**, **cell-range selection + copy**, grouping, tree,
  and master/detail when you need them.
- **Accessibility** - WAI-ARIA grid roles and keyboard navigation built
  in, instead of a plain `<table>`.

## What you give up

- The **tiny footprint** of a styled `<table>` for a truly static list.
- A **pixel-perfect**, zero-config match with the rest of the kit - you
  re-create the look with tokens instead (a one-time setup).

## Frequently asked questions

### When should I replace a Flowbite / Skeleton / shadcn table with a data grid?

When the table needs sorting, filtering, virtualization, inline editing, or
large datasets. These styled `<Table>` components are presentation only;
once you are hand-writing table behaviour, a data grid like SvGrid removes
that code. (shadcn-svelte also ships a separate TanStack-based data table -
see [that migration guide](https://svgrid.com/docs/help/migrating-from-shadcn-data-table/).)

### Can SvGrid match my existing UI-kit styling?

Yes. SvGrid themes through `--sg-*` CSS variables, which you can wire to your
Tailwind / design-system tokens so it matches Flowbite, Skeleton, or
shadcn-svelte.

### Is it overkill for a small static table?

For a small, static table that never sorts or filters, a styled `<table>` is
lighter and fine. Switch when the behaviour - not just the styling - becomes the
work.

## What you end up with

Everything the presentational table could not do: sort, filter, page, edit.

```svelte
<SvGrid data={rows} {columns} sortable filterable pageable pageSize={3} editable />
```

## See also

- [SvGrid vs UI-kit tables](https://svgrid.com/compare/svelte-ui-kit-tables/) - the side-by-side comparison
- [Tailwind integration](https://svgrid.com/docs/help/tailwind/) - match your design system
- [Getting started](https://svgrid.com/docs/getting-started/) - a working grid in ~15 lines

---

SvGrid is the Svelte 5 data grid (`npm install @svgrid/grid`, MIT). This page: https://svgrid.com/docs/help/migrating-from-ui-kit-tables/ . All docs: https://svgrid.com/llms.txt
