# Table

> Svelte Lean Table: the capability levels from Table to Data Grid, measured sizes per entry point, and the full specimen index.

Page: https://svelte-lean.vercel.app/table · Markdown: https://svelte-lean.vercel.app/table.md · Index: https://svelte-lean.vercel.app/llms.txt

A data table for Svelte 5 that renders a native \<table\> and grows into a data grid through props and separately imported modules.

- **Source**: packages/tableREADME.mdindex.ts (exports)
- **Tests**: tests/table.spec.ts (browser)
- **Fixture**: fixtures/table-basic
- **Benchmark**: table.bench.spec.ts

## At a glance

Search, selection, column controls and paging are props. Sort a column, select rows, hide a column.

`members.svelte`

```svelte
<script lang="ts">
	import '@svelte-lean/table/style.css';
	import { DataTable, type Column } from '@svelte-lean/table';

	type Member = { id: number; name: string; team: string; revenue: number };
	let { members }: { members: Member[] } = $props();

	const columns: Column<Member>[] = [
		{ id: 'name', header: 'Name' },
		{ id: 'team', header: 'Team' },
		{ id: 'revenue', header: 'Revenue', align: 'end' }
	];
</script>

<DataTable
	data={members}
	{columns}
	getRowId={(row) => row.id}
	label="Members"
	searchable
	selection="multiple"
	columnControls
	state={{ pageSize: 6 }}
/>
```

- The output is a `<table>` with caption, scope and `aria-sort`; it renders on the server.
- State is one plain, serializable object you can control from outside; every string is a message.
- A cell is a component only when you pass a snippet. The engine underneath, `createTable()`, and the Svelte-free `@svelte-lean/table/core` are documented under [Engine](https://svelte-lean.vercel.app/table/api.md#engine).

## Capability levels

One component; a table pays only for the levels it uses.

| Level | Adds | How | Status |
| --- | --- | --- | --- |
| Table | A native \<table\> with caption, colgroup, thead, tbody, tfoot, scope and aria-sort; snippets for cells; SSR. | \<DataTable /\> with the three required props | shipped |
| DataTable | Sorting, search and filters, selection, pagination, expansion and tree rows, pinning, resizing, visibility and order, sticky header, states, messages. | Props; state in one object | shipped |
| Virtual Table | A windowed body for very large row counts. | A future opt-in (@svelte-lean/virtual), extracted only when a reusable need is proved | not shipped |
| Data Grid | Cell focus and arrow-key navigation, inline editing, range selection, copy and paste, grouping and pivot, persisted state, server data sources. | Props that switch the keyboard model on, plus separate entry points | shipped, rows not virtualized |

Rows are not virtualized. A project that needs virtual rows today needs another package.

## What a build ships

The `table-basic` fixture (`DataTable` and its stylesheet, Vite 7.3.6, Svelte 5.57.1, production build) ships 20841 B brotli of Svelte Lean code, plus Svelte's runtime (15980 B brotli). Its module graph is asserted to exclude grouping.js, pivot.js, clipboard.js, export.js, server.js, state.js (55 checks passed).

### Entry points

| Entry | File | Contains | gzip | brotli | Budget (gzip) |
| --- | --- | --- | --- | --- | --- |
| renderer | dist/index.js | the root entry: \<DataTable /\>, createTable(), helpers, messages | 24816 B | 21768 B | 24900 B |
| headless | dist/core.js | the ./core entry: pure row model functions, no Svelte | 2665 B | 2440 B | 2700 B |
| engine | dist/table.svelte.js | createTable() on its own (runes) | 3538 B | 3244 B | 3600 B |
| grouping | dist/grouping.js | groupBy(), summarize(), aggregate() | 2149 B | 1962 B | 2400 B |
| pivot | dist/pivot.js | pivot() | 526 B | 470 B | 600 B |
| editing | dist/editing.js | applyEdit(), setValue(), parseEdit(), createHistory() | 707 B | 617 B | 800 B |
| csv | dist/export.js | toCsv(), parseDelimited(), downloadText() | 741 B | 646 B | 850 B |
| clipboard | dist/clipboard.js | copyRange(), pasteRange(), rangeBounds() | 895 B | 803 B | 1000 B |
| server | dist/server.js | createDataSource() | 369 B | 310 B | 425 B |
| state | dist/state.js | serializeState(), restoreState() | 796 B | 711 B | 900 B |
| styles | dist/style.css | style.css | 9086 B | 7896 B | 9100 B |

Each entry bundled independently with esbuild (bundle + minify, ESM); shared code is counted per entry here and de-duplicated by consumer bundlers. Svelte peer runtime excluded. gzip level 9 / brotli quality 11 (node:zlib). Budgets are gzip. Each entry is measured on its own; a bundler de-duplicates shared code, so entries do not add up.

## Timings

Medians of the playground benchmark, every row in the document.

| Subject | Median | p95 | Method |
| --- | --- | --- | --- |
| Mount, one thousand rows | 287.3 ms | 303 ms | component init to the second animation frame after onMount, client render of the whole table (ssr=false); median of 5 loads |
| Sort by revenue, one thousand rows | 156.1 ms | 161 ms | header button click (ascending by revenue) to the second animation frame; median of 5 |
| Mount, ten thousand rows | 3088.2 ms | 3139.1 ms | component init to the second animation frame after onMount, client render of the whole table (ssr=false); median of 5 loads |
| Sort by revenue, ten thousand rows | 1599.5 ms | 1618.5 ms | header button click (ascending by revenue) to the second animation frame; median of 5 |

chromium 153.0.8010.12, AMD EPYC 9555P 64-Core Processor, linux 6.12.107+deb13-cloud-amd64, Node v22.23.3, production build, run 2026-10-05. [Methodology](https://svelte-lean.vercel.app/performance/methodology.md)

## Specimens

Every specimen is a live `DataTable` with its source, on the page of its feature.

| Essentials | [Basic table](https://svelte-lean.vercel.app/table/getting-started.md#basic-table) · [Custom cells](https://svelte-lean.vercel.app/table/columns.md#custom-cells) · [Sorting](https://svelte-lean.vercel.app/table/sorting.md#single-and-multi-column) · [Filtering and search](https://svelte-lean.vercel.app/table/filtering.md#search-and-column-filters) · [Pagination](https://svelte-lean.vercel.app/table/pagination.md#client-pagination) · [Row selection](https://svelte-lean.vercel.app/table/selection.md#multiple-selection) |
| --- | --- |
| Layout | [Density and borders](https://svelte-lean.vercel.app/table/layout.md#density-and-borders) · [Fixed header](https://svelte-lean.vercel.app/table/layout.md#sticky-header) · [Fixed columns](https://svelte-lean.vercel.app/table/columns.md#pinned-columns) · [Grouped headers](https://svelte-lean.vercel.app/table/columns.md#grouped-headers) · [Column visibility](https://svelte-lean.vercel.app/table/columns.md#visibility) · [Resize and reorder](https://svelte-lean.vercel.app/table/columns.md#resize-and-reorder) · [Ellipsis](https://svelte-lean.vercel.app/table/columns.md#ellipsis) · [Cell spans](https://svelte-lean.vercel.app/table/columns.md#cell-spans) · [Right-to-left](https://svelte-lean.vercel.app/table/localization-rtl.md#right-to-left) |
| Rows | [Expandable rows](https://svelte-lean.vercel.app/table/rows.md#expandable-rows) · [Tree data](https://svelte-lean.vercel.app/table/rows.md#tree-data) · [Row grouping](https://svelte-lean.vercel.app/table/grouping-pivot.md#row-grouping) · [Row reordering](https://svelte-lean.vercel.app/table/rows.md#row-reordering) · [Row events](https://svelte-lean.vercel.app/table/rows.md#row-events) · [Row animation](https://svelte-lean.vercel.app/table/rows.md#row-animation) |
| Workflows | [Editing and history](https://svelte-lean.vercel.app/table/editing.md#cell-editing-and-history) · [Range and clipboard](https://svelte-lean.vercel.app/table/clipboard-export.md#range-selection-and-clipboard) · [CSV export](https://svelte-lean.vercel.app/table/clipboard-export.md#csv-export) · [Server data](https://svelte-lean.vercel.app/table/server-data.md#manual-mode) · [Persisted state](https://svelte-lean.vercel.app/table/state-persistence.md#serialize-and-restore) · [Loading and empty](https://svelte-lean.vercel.app/table/server-data.md#loading-error-and-empty-states) · [Localization](https://svelte-lean.vercel.app/table/localization-rtl.md#messages) |
| Analysis | [Summaries](https://svelte-lean.vercel.app/table/grouping-pivot.md#summaries) · [Pivot](https://svelte-lean.vercel.app/table/grouping-pivot.md#pivot) · [Performance](https://svelte-lean.vercel.app/performance/results.md#table-1000-rows) |

## Read next

- [Getting started](https://svelte-lean.vercel.app/table/getting-started.md)
- [Data Grid](https://svelte-lean.vercel.app/table/data-grid.md)
- [API reference](https://svelte-lean.vercel.app/table/api.md)
