@svgrid/mcp 3.0.9 → 3.0.11
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.
- package/dist/data.js +8 -8
- package/dist/preview.d.ts +1 -1
- package/dist/preview.js +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
package/dist/data.js
CHANGED
|
@@ -3928,9 +3928,9 @@ export const docs = [
|
|
|
3928
3928
|
{
|
|
3929
3929
|
"slug": "getting-started-full",
|
|
3930
3930
|
"path": "docs/getting-started-full.md",
|
|
3931
|
-
"title": "Getting
|
|
3931
|
+
"title": "Getting started: the complete guide on one page",
|
|
3932
3932
|
"section": "Overview",
|
|
3933
|
-
"markdown": "# Getting Started with SvGrid\n\nSvGrid is a modern, production-ready data grid for Svelte 5 - a headless\ncore engine paired with a Svelte render component\n(`<SvGrid>`). It scales from a 10-row read-only table to a virtualized\n100,000-row, 100-column editing surface with grouping, multi-column\nfiltering, server-side data, and full keyboard and screen-reader\nsupport.\n\nThis page walks you from `pnpm add` to a feature-complete grid. It is\nthe canonical entry point - every other page in the documentation\nassumes you've finished this one. Estimated reading time: 15 minutes.\n\n> **New here?** Two short companion reads:\n>\n> - [Why headless?](./why-headless.md) - the architecture decision\n> behind the `createSvGrid` core vs. the `<SvGrid>` renderer.\n> - [Tailwind integration](./help/tailwind.md) - how `--sg-*` custom\n> properties + Tailwind v4 + dark mode fit together.\n\n> `@svgrid/grid` is published under the **MIT License** - permissive\n> for commercial use, redistribution, and modification. The paid companion\n> `@svgrid/enterprise` (data export + print) ships under a separate commercial\n> license. See [LICENSE](../LICENSE) and\n> [packages/enterprise/LICENSE](../packages/enterprise/LICENSE).\n\n---\n\n## Contents\n\n1. [Your first grid in 60 seconds](#1-your-first-grid-in-60-seconds)\n2. [Install the package](#2-install-the-package)\n3. [Provide row data](#3-provide-row-data)\n4. [Define column definitions](#4-define-column-definitions)\n5. [Register features (row models)](#5-register-features-row-models)\n6. [Styling: theme, density, dark mode](#6-styling-theme-density-dark-mode)\n7. [Sizing the grid](#7-sizing-the-grid)\n8. [Custom cells with FlexRender](#8-custom-cells-with-flexrender)\n9. [Sorting, filtering, pagination](#9-sorting-filtering-pagination)\n10. [Selection, editing, keyboard](#10-selection-editing-keyboard)\n11. [Server-side data](#11-server-side-data)\n12. [Virtualization for large datasets](#12-virtualization-for-large-datasets)\n13. [Accessibility](#13-accessibility)\n14. [TypeScript notes](#14-typescript-notes)\n15. [What's next](#15-whats-next)\n\n---\n\n## 1. Your first grid in 60 seconds\n\nEvery example below runs against this setup:\n\n```svelte {preamble}\n<script lang=\"ts\">\n import { SvGrid, tableFeatures, rowSortingFeature, columnFilteringFeature, rowPaginationFeature, type ColumnDef } from '@svgrid/grid'\n\n type Person = { id: number; name: string; email: string; age: number; city: string }\n\n const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, rowPaginationFeature })\n\n let rows = $state<Person[]>([\n { id: 1, name: 'Ada Lovelace', email: 'ada@example.com', age: 36, city: 'London' },\n { id: 2, name: 'Grace Hopper', email: 'grace@example.com', age: 45, city: 'New York' },\n { id: 3, name: 'Linus Torvalds', email: 'linus@example.com', age: 54, city: 'Portland' },\n ])\n const data = rows\n\n const columns: ColumnDef<typeof features, Person>[] = [\n { field: 'name', header: 'Name' },\n { field: 'email', header: 'Email' },\n { field: 'age', header: 'Age', width: 90 },\n { field: 'city', header: 'City' },\n ]\n</script>\n```\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n\n type Person = { firstName: string; age: number; status: string }\n\n const rows: Person[] = [\n { firstName: 'Ada', age: 36, status: 'active' },\n { firstName: 'Linus', age: 54, status: 'active' },\n { firstName: 'Grace', age: 85, status: 'inactive' },\n ]\n\n const columns: GridColumns<Person> = [\n { field: 'firstName', header: 'First name' },\n { field: 'age', header: 'Age' },\n { field: 'status', header: 'Status' },\n ]\n</script>\n\n<SvGrid data={rows} columns={columns} />\n```\n\nThat's a complete, working grid. The rest of this page is about turning\nit into something you'd ship.\n\n---\n\n## 2. Install the package\n\nSvGrid is a single npm package. There is no peer dependency on a CSS\nframework - bring your own, or use the bundled stylesheet.\n\n```bash\n# pnpm (recommended)\npnpm add @svgrid/grid\n\n# npm\nnpm install @svgrid/grid\n\n# yarn\nyarn add @svgrid/grid\n```\n\n**Requirements.**\n\n- Svelte **5.x** (uses runes - `$state`, `$derived`, `$effect`).\n- TypeScript **5.4+** (optional but recommended).\n- Node **18+** for tooling.\n\nOnce installed, import the component, the features you want, and the\nmatching `ColumnDef` type:\n\n```ts\nimport {\n SvGrid,\n tableFeatures,\n rowSortingFeature,\n columnFilteringFeature, type GridColumns,\n} from '@svgrid/grid'\n```\n\nThe bundle is tree-shakeable - features you don't import don't ship. The\ndefault render component (`<SvGrid>`) brings its own scoped CSS, so\nthere's no separate stylesheet to import. Re-theming happens via the\n`--sg-*` custom-property surface; see\n[Tailwind integration](./help/tailwind.md) for the full list.\n\n---\n\n## 3. Provide row data\n\nSvGrid is data-agnostic. The `data` prop is any\n`ReadonlyArray<TRow>` - a Svelte 5 `$state` array, a derived store, an\nSWR/React-query-style cache, the result of a `+page.ts` load function,\nor a plain literal.\n\n```svelte\n<script lang=\"ts\">\n import { SvGrid } from '@svgrid/grid'\n\n type Person = { id: string; firstName: string; age: number }\n\n // Reactive: pushing into `rows` updates the grid automatically.\n let rows = $state<Person[]>([\n { id: '1', firstName: 'Ada', age: 36 },\n { id: '2', firstName: 'Linus', age: 54 },\n ])\n\n function addRow() {\n rows.push({ id: crypto.randomUUID(), firstName: 'New', age: 0 })\n }\n</script>\n\n<button onclick={addRow}>Add row</button>\n<SvGrid data={rows} columns={columns} />\n```\n\n**Identity.** Today the wrapper uses the row's array index as its id.\nThat is fine for read-only data; if you mutate `rows`, prefer keeping\nthe same object references for rows that didn't change so selection\nand edit state line up. A `getRowId` prop on the wrapper is tracked in\n[Missing features](./help/missing-features.md) and supported by the\nheadless `createSvGrid` core today.\n\n**Immutability.** SvGrid never mutates your data. When you edit a cell\nthe grid emits an event; you decide whether to mutate in place or copy.\nSee [§10 - Editing](#10-selection-editing-keyboard).\n\n---\n\n## 4. Define column definitions\n\nA column definition tells SvGrid how to read a value out of a row, how\nto render it, and which features apply to it.\n\n```ts\nimport type { ColumnDef } from '@svgrid/grid'\n\ntype Person = {\n id: string\n firstName: string\n lastName: string\n age: number\n joinedAt: string // ISO date\n salary: number\n active: boolean\n}\n\nconst columns: GridColumns<Person> = [\n // `field`: read a key straight off the row\n { field: 'firstName', header: 'First name' },\n\n // `fieldFn`: compute the value; needs an explicit `id`\n {\n id: 'fullName',\n header: 'Full name',\n fieldFn: (row) => `${row.firstName} ${row.lastName}`,\n },\n\n // Numeric with locale-aware formatting\n {\n field: 'age',\n header: 'Age',\n format: { type: 'number', options: { maximumFractionDigits: 0 } },\n },\n\n // Date with explicit pattern\n {\n field: 'joinedAt',\n header: 'Joined',\n format: { type: 'date', pattern: 'y-m-d' },\n },\n\n // Currency\n {\n field: 'salary',\n header: 'Salary',\n format: { type: 'currency', currency: 'USD' },\n },\n\n // Boolean rendered as a checkbox\n {\n field: 'active',\n header: 'Active',\n editorType: 'checkbox',\n },\n]\n```\n\n**Common properties.**\n\n| Property | Purpose |\n| --- | --- |\n| `field` | Reads `row[key]`. |\n| `fieldFn` | Computes the value from the row. |\n| `id` | Stable column id (required if you use `fieldFn`). |\n| `header` | String or render snippet for the header. |\n| `footer` | String or render snippet for the footer row. |\n| `cell` | Render snippet/component for the body cell. |\n| `format` | Locale-aware formatter (`number`, `currency`, `percent`, `date`). |\n| `formatter` | Function for one-off custom value formatting. |\n| `editorType` | Inline editor: `text` \\| `number` \\| `checkbox` \\| `date` \\| `datetime`. |\n| `width` | Initial column width in pixels (default `columnWidth` prop). |\n| `align` | Header + body alignment: `'left'` \\| `'right'` \\| `'center'`. Inferred from `editorType` when omitted. |\n| `columns` | Child column defs (for column groups). |\n\nSorting / filtering / grouping are toggled per-grid via the registered\nfeatures - there is no per-column `enableSorting` / `enableColumnFilter`\nflag yet; those entries are in [Missing features](./help/missing-features.md).\n\nSee [`packages/grid/src/core.ts`](../packages/grid/src/core.ts)\nfor the full type.\n\n---\n\n## 5. Register features (row models)\n\nThe grid engine is feature-gated. Out of the box you get the **core row\nmodel** (the rows in their original order). To enable sorting,\nfiltering, grouping, expansion, pagination, or selection you opt in\nwith `tableFeatures(...)` and the matching `create*RowModel` factory.\n\n```svelte\n<script lang=\"ts\">\n import {\n SvGrid,\n tableFeatures,\n rowSortingFeature,\n columnFilteringFeature,\n rowSelectionFeature, type GridColumns,\n } from '@svgrid/grid'\n\n const features = tableFeatures({\n rowSortingFeature,\n columnFilteringFeature,\n rowSelectionFeature,\n })\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n showPagination={true}\n pageSize={25}\n/>\n```\n\n**Rule of thumb.** Only register the features you use. The wrapper wires\nthe matching row-model pipeline (core → filtered → sorted → grouped →\nexpanded) for you and exposes the user-facing toggles via props\n(`showPagination`, `filterMode`, `showRowSelection`, …). If you need the\nheadless pipeline directly - e.g. a custom renderer - drop down to\n`createSvGrid` from the same package; see [Why headless?](./why-headless.md).\n\n| Feature | Factory | What it does |\n| --- | --- | --- |\n| `rowSortingFeature` | `createSortedRowModel` | Click headers to sort; shift-click for multi-sort. |\n| `columnFilteringFeature` | `createFilteredRowModel` | Per-column filters with built-in `filterFns`. |\n| `rowPaginationFeature` | `createPaginatedRowModel` | Page slicing + footer state. |\n| `rowSelectionFeature` | - | Row checkboxes, range selection, headless API. |\n| `columnGroupingFeature` | `createGroupedRowModel` | Group-by-column + aggregators. |\n| `rowExpandingFeature` | `createExpandedRowModel` | Tree / master-detail expansion. |\n\n---\n\n## 6. Styling: theme, density, dark mode\n\nSvGrid's render component (`<SvGrid>`) ships its own scoped styles. You\nre-theme it by declaring `--sg-*` custom properties at any level above\nthe grid - the included light, dark, and high-contrast palettes in the\n[`10-custom-cells-and-themes`](../examples/src/demos/10-custom-cells-and-themes.svelte)\ndemo are themselves just three sets of these tokens applied via\n`style=\"--sg-bg: …; --sg-fg: …; …\"`.\n\n**Customising tokens.** Override at any level - `:root`, a wrapper, or\ndirectly on `<SvGrid>`.\n\n```css\n:root {\n --sg-header-bg: #f6f7f9;\n --sg-header-fg: #1f2933;\n --sg-row-hover-bg: #eef2ff;\n --sg-selection-bg: #dbeafe;\n --sg-border: #e5e7eb;\n --sg-focus-ring: 0 0 0 2px #2563eb;\n --sg-font: 'Inter', system-ui, sans-serif;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --sg-header-bg: #0f172a;\n --sg-header-fg: #f1f5f9;\n --sg-row-hover-bg: #1e293b;\n --sg-border: #334155;\n }\n}\n```\n\n**Density.** Row height is the one piece of the look that is a prop\nrather than a token - the virtualizer needs it as a number, and the\ngrid writes it as an inline style on each row. Pass `rowHeight`\n(default `30`): `28` for compact, `48` for comfortable. Changing it\ndoes not remount the virtualizer.\n\n**Reduced motion.** Sort animations and expand transitions respect\n`prefers-reduced-motion: reduce` automatically.\n\n---\n\n## 7. Sizing the grid\n\nThe grid's scroll shell is sized by `containerHeight`, which defaults to\n520 px. A number is pixels; a string is passed through to CSS, so `'100%'`\nfills the parent and `'auto'` grows to the content.\n\n```svelte {runnable}\n<!-- Fixed: 600px tall. The typical choice. -->\n<SvGrid data={rows} columns={columns} containerHeight={600} />\n\n<!-- Flexible: fills a parent that sets the height itself. -->\n<div class=\"grid-shell\">\n <SvGrid data={rows} columns={columns} containerHeight=\"100%\" />\n</div>\n\n<style>\n .grid-shell {\n height: calc(100dvh - 4rem);\n }\n</style>\n```\n\n**Auto-height (small datasets only).** For grids with fewer than ~200\nrows you can let the grid grow to its content. Turn row virtualization\noff as well - a shell with no fixed height gives the virtualizer nothing\nto measure against:\n\n```svelte {runnable}\n<SvGrid\n data={rows}\n columns={columns}\n containerHeight=\"auto\"\n virtualization={false}\n/>\n```\n\nDon't use this for large data: every row renders.\n\n---\n\n## 8. Custom cells with FlexRender\n\nFor anything beyond a stringified value, render with `FlexRender`,\n`renderComponent`, or `renderSnippet`.\n\n### As a Svelte snippet\n\n```svelte\n<script lang=\"ts\">\n import { renderSnippet, type GridColumns } from '@svgrid/grid'\n</script>\n\n{#snippet StatusCell({ value }: { value: string })}\n <span class=\"pill pill-{value}\">{value}</span>\n{/snippet}\n\n<script lang=\"ts\">\n const columns: GridColumns<Person> = [\n {\n field: 'status',\n header: 'Status',\n cell: renderSnippet(StatusCell, (ctx) => ({ value: ctx.getValue() as string })),\n },\n ]\n</script>\n```\n\n### As a Svelte component\n\n```ts\nimport StatusBadge from './StatusBadge.svelte'\nimport { renderComponent } from '@svgrid/grid'\n\nconst columns = [\n {\n field: 'status',\n header: 'Status',\n cell: renderComponent(StatusBadge, (ctx) => ({ status: ctx.getValue() })),\n },\n]\n```\n\n`renderComponent` and `renderSnippet` both receive a\n`CellContext` so you can read sibling values, mutate state, or call\nback into the grid via `ctx.table`.\n\n---\n\n## 9. Sorting, filtering, pagination\n\nOnce their features are registered (see §5) the UI affordances appear\nautomatically. The state is controllable.\n\n**Quick way - capability shortcuts.** Every capability is off by default;\nthe fastest way to opt in is a boolean shortcut prop, no feature constants\nrequired. `sortable` and `filterable` inject the matching feature for you;\n`editable`, `groupable`, and `pageable` alias `enableInlineEditing`,\n`showGroupingControls`, and `showPagination`:\n\n```svelte {runnable}\n<SvGrid data={rows} columns={columns} sortable filterable editable groupable pageable />\n```\n\nReach for the explicit `features` set + fine-grained props below when you\nneed more control (filter mode, page size, per-column opt-outs).\n\n### Uncontrolled (the default)\n\nThe wrapper owns sort, filter, pagination, selection, and expansion\nstate by default. Set the initial page size and which filter UI to\nshow via props:\n\n```svelte {runnable}\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n showPagination={true}\n pageSize={50}\n filterMode=\"menu\"\n/>\n```\n\n### Observable (callbacks fire when state changes)\n\nThe wrapper still owns the state, but emits callbacks on every change.\nUse this when an outside piece of UI needs to react (a \"X rows\nselected\" pill, a router that syncs sort to the URL, a server fetch).\n\n```svelte {runnable}\n<script lang=\"ts\">\n let sorting = $state<Array<{ id: string; desc: boolean }>>([])\n let filters = $state<Array<{ id: string; operator: string; value: string }>>([])\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n onSortingChange={(next) => (sorting = next)}\n onFiltersChange={(next) => (filters = next.columns)}\n/>\n```\n\n### External (you own row ordering / filtering)\n\nFor server-side data or tree-structured data the wrapper records the\nsort + filter UI state but does **not** re-order the rows - you do.\nPair `externalSort` / `externalFilter` with the callbacks above:\n\n```svelte\n<SvGrid\n data={preFilteredRows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n externalSort={true}\n externalFilter={true}\n onSortingChange={(next) => fetchPage({ sort: next, page: 0 })}\n onFiltersChange={(next) => fetchPage({ filters: next.columns, page: 0 })}\n/>\n```\n\nFor Excel-style filter operators and the active-filter chip UI, see\n[`applyExcelFilter`](../packages/grid/src/filtering/excel-filters.ts).\n\n---\n\n## 10. Selection, editing, keyboard\n\n### Row selection\n\n```svelte {runnable}\n<script lang=\"ts\">\n let selected = $state<Person[]>([])\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n selectionMode=\"row\"\n showRowSelection={true}\n onRowSelectionChange={(_state, rows) => (selected = rows)}\n/>\n\n{#if selected.length}\n <p>{selected.length} selected</p>\n{/if}\n```\n\n`selectionMode` is the umbrella prop: `'row'` shows the checkbox\ncolumn, `'cell'` enables click-and-drag range selection,\n`'both'` (default) enables both, `'none'` disables both. The\n`onRowSelectionChange` callback receives the selection record AND the\nmaterialised row array.\n\n### Cell editing\n\nSet `editorType` on each editable column. The grid handles entry,\ncommit, and cancel; you handle persistence.\n\n```svelte\n<script lang=\"ts\">\n function handleCellEdit(event: {\n rowId: string\n columnId: string\n value: unknown\n }) {\n const row = rows.find((r) => r.id === event.rowId)\n if (!row) return\n ;(row as Record<string, unknown>)[event.columnId] = event.value\n }\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n getRowId={(row) => row.id}\n onCellValueChange={handleCellEdit}\n/>\n```\n\n### Keyboard\n\nThe grid follows the WAI-ARIA grid pattern:\n\n| Keys | Action |\n| --- | --- |\n| `←` `↑` `→` `↓` | Move active cell |\n| `Home` / `End` | First / last column of the row |\n| `Ctrl+Home` / `Ctrl+End` | First / last cell of the grid |\n| `PageUp` / `PageDown` | Move one viewport |\n| `Shift + <move>` | Extend cell-range selection |\n| `Space` | Toggle row selection (when selection enabled) |\n| `Enter` / `F2` | Begin editing the active cell |\n| `Esc` | Cancel edit / clear selection |\n| `Ctrl/Cmd + C` | Copy selection as TSV |\n| `Ctrl/Cmd + V` | Paste TSV into selection |\n\nIf you implement your own header or toolbar, route keys through\n`getKeyboardIntent` and `getNextActiveCell` so behaviour stays\nconsistent.\n\n---\n\n## 11. Server-side data\n\nFor datasets that don't fit in memory, drive the grid from the server.\nThe pattern is: turn the wrapper's `onSortingChange` /\n`onFiltersChange` callbacks into a query, fetch, hand the page back as\n`data`, and use the `externalSort` + `externalFilter` props so the grid\ndoesn't try to re-order rows it didn't fetch.\n\n```svelte\n<script lang=\"ts\">\n import { SvGrid, tableFeatures, rowSortingFeature,\n columnFilteringFeature } from '@svgrid/grid'\n\n const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })\n\n let sort = $state<Array<{ id: string; desc: boolean }>>([])\n let filters = $state<Array<{ id: string; operator: string; value: string }>>([])\n let page = $state(0)\n const pageSize = 50\n\n let rows = $state<Person[]>([])\n let total = $state(0)\n let loading = $state(false)\n let controller: AbortController | null = null\n\n async function load() {\n controller?.abort()\n controller = new AbortController()\n loading = true\n try {\n const res = await fetch('/api/people?' + new URLSearchParams({\n sort: JSON.stringify(sort),\n filters: JSON.stringify(filters),\n page: String(page),\n size: String(pageSize),\n }), { signal: controller.signal })\n const body = await res.json()\n rows = body.rows\n total = body.total\n } catch (err) {\n if ((err as Error).name !== 'AbortError') throw err\n } finally {\n loading = false\n }\n }\n\n $effect(() => { sort; filters; page; load() })\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n externalSort={true}\n externalFilter={true}\n showPagination={false}\n onSortingChange={(next) => { sort = next; page = 0 }}\n onFiltersChange={(next) => { filters = next.columns; page = 0 }}\n/>\n\n<nav>\n <button onclick={() => (page = Math.max(0, page - 1))}\n disabled={page === 0 || loading}>‹ Prev</button>\n <span>Page {page + 1} of {Math.ceil(total / pageSize)}</span>\n <button onclick={() => (page = page + 1)}\n disabled={(page + 1) * pageSize >= total || loading}>Next ›</button>\n</nav>\n\n{#if loading}<div class=\"overlay\">Loading…</div>{/if}\n```\n\nThe `external*` props tell the grid not to re-derive that dimension\nlocally - the data you pass in is already the answer. Pagination above\nis hand-rolled so total-row-count and \"show next page\" stay in your\ncontrol; if a built-in pager is enough, leave `showPagination={true}`\non and the wrapper will page the local `rows` array (which, in this\nserver-side pattern, only ever holds one page anyway).\n\nSee the [`09-server-side` demo](../examples/src/demos/09-server-side.svelte)\nfor a complete runnable version with debounce, abort wiring, and a\n60 ms mock latency.\n\n---\n\n## 12. Virtualization for large datasets\n\nRow and column virtualization are both **on by default** - you opt out,\nnot in. `virtualization={false}` and `columnVirtualization={false}` render\nevery row / column, which is what you want for a short grid you intend to\nprint, or when sticky column pinning has to survive (the column virtualizer\nrecycles DOM nodes, so the two cannot co-exist).\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid } from '@svgrid/grid'\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n rowHeight={36}\n overscan={6}\n/>\n```\n\n`rowHeight` takes a number (default 30) or a `(rowIndex) => px` function for\nper-row heights. When row content varies and you cannot predict it, set\n`autoRowHeight` instead and the grid measures each row. `overscan` (default 8)\nis how many rows beyond the viewport stay mounted.\n\nFor full control (e.g. variable row heights, programmatic scroll),\nuse the headless virtualizer directly:\n\n```ts\nimport { createSvelteVirtualizer } from '@svgrid/grid'\n\nconst virtualizer = createSvelteVirtualizer({\n count: () => rows.length,\n getScrollElement: () => scrollRef,\n estimateSize: (index) => (rows[index].kind === 'header' ? 40 : 28),\n overscan: 6,\n})\n\n// Programmatic scroll:\nvirtualizer.scrollToIndex(75_432, { align: 'center' })\n```\n\nSee [`packages/grid/src/virtualization/`](../packages/grid/src/virtualization/)\nfor the full API.\n\n---\n\n## 13. Accessibility\n\nSvGrid implements the WAI-ARIA 1.2 grid pattern.\n\n- The root carries `role=\"grid\"`, an accessible name (set via\n `aria-label` or `aria-labelledby`), and `aria-rowcount` /\n `aria-colcount` reflecting the total - not just the visible window.\n- Rows carry `role=\"row\"` plus `aria-rowindex` accounting for the\n virtualized offset; cells carry `role=\"gridcell\"` and `aria-colindex`.\n- The active cell is always exactly one focusable element\n (roving `tabindex`); arrow keys move it.\n- Sort columns carry `aria-sort=\"ascending\" | \"descending\" | \"none\"`.\n- Sort and selection state changes are announced via an off-screen\n `aria-live` region the grid manages internally.\n\nIf you build your own header or toolbar, use the helpers in\n[`a11y.ts`](../packages/grid/src/a11y.ts) so your markup\nstays consistent with the contract:\n\n```ts\nimport {\n getGridRootA11yProps,\n getGridRowA11yProps,\n getGridCellA11yProps,\n getGridHeaderA11yProps,\n} from '@svgrid/grid'\n```\n\nThere is a contract test suite at\n[`a11y.contract.test.ts`](../packages/grid/src/a11y.contract.test.ts)\nthat exercises the public a11y guarantees - run it (`pnpm test`) when\nyou customize markup to be sure you haven't regressed the contract.\n\n---\n\n## 14. TypeScript notes\n\nMost APIs are generic over your row type. Define the row type once and\nflow it through:\n\n```ts\ntype Person = { id: string; firstName: string; age: number }\n\nconst columns: GridColumns<Person> = [\n { field: 'firstName', header: 'First name' }, // ✅ key checked\n // { field: 'first_name', header: '…' }, // ✗ TS error\n]\n```\n\nThe first type parameter is the **feature set**. When you register\nfeatures, derive it once and reuse:\n\n```ts\nconst features = tableFeatures({\n rowSortingFeature,\n rowSelectionFeature,\n columnFilteringFeature,\n})\n\ntype Features = typeof features\n\nconst columns: ColumnDef<Features, Person>[] = [/* … */]\n```\n\nThis lets feature-specific column properties (like `filterFn`)\nauto-complete and type-check.\n\n---\n\n## 15. What's next\n\n### Core features\n\n- **[Examples gallery](https://svgrid.com/demos/)** - 50+ production-quality\n demos, from quick-start to 100k-row virtualization.\n- **[Column definitions](./help/columns/column-definitions.md)** - every\n property on `ColumnDef`.\n- **[Row sorting](./help/rows/row-sorting.md)** and the wider [rows topic index](./help/index.md#rows) -\n when to use which row model and the order they run in.\n- **[Tree rows (expand / collapse)](./help/rows/tree-rows.md)** - the\n flat-array + expanded-map pattern, connector lines, keyboard\n navigation, and lazy load on first expand.\n- **[Filter API](./help/filtering/filter-api.md)** - sort, filter,\n paginate, group, and aggregate locally or against your backend.\n- **[Tailwind integration](./help/tailwind.md)** - full list of CSS\n custom properties (`--sg-*`) and recipes for building your own theme.\n- **[Compare SvGrid with other Svelte data grids](https://svgrid.com/compare/)** -\n side-by-side feature matrix and when to pick which.\n\n### Enterprise features (`@svgrid/enterprise`)\n\nThe paid companion package augments your `SvGridApi` with one\n`installEnterprise(api)` call. Set a license key at app boot to remove the\n\"unlicensed\" watermark - every feature still runs without a key for\ndemos and evaluation.\n\n- **[Data export and printing](./help/export.md)** - Excel (xlsx), PDF,\n CSV, TSV, HTML, and a paginated print view. Defaults to the currently\n displayed rows so sort + filter + paginate carry through automatically.\n- **[Data import](./help/import.md)** - Excel (xlsx), CSV, TSV, and JSON\n with column mapping, per-row validation, and preview-before-commit. Auto-\n detects the format from the file extension or pasted text.\n- **[Pivot tables](./help/pivot.md)** - drag-and-drop Pivot Designer with\n Filters / Rows / Columns / Values zones, multi-level column headers,\n per-measure aggregator picker, pivot-aware sort. Built on the same\n engine; no special \"pivot mode\".\n- **[AI assistant](./help/ai.md)** - natural-language filter, smart fill,\n summarise, and classify, driven by a bring-your-own model adapter\n (`setAIProvider(fn)`). Ships with a deterministic `mockAIProvider` so\n the demo works without keys.\n\n### Getting help\n\n- File issues at the [project repository](https://github.com/sv-grid/sv-grid/issues).\n- Browse the [Help index](./help/index.md) for topic-oriented guides.\n- Use the [@svgrid/mcp](https://svgrid.com/mcp/) server\n to give your AI assistant accurate answers.\n- Read the source - it is small, well-commented, and meant to be read\n before opening a bug report.\n\n### License\n\n`@svgrid/grid` is published under the **MIT License**. Free for\ncommercial and personal use. The paid `@svgrid/enterprise` companion package\n(export, import, print, pivot, AI assistant) is governed by a separate\ncommercial license. See [LICENSE](../LICENSE) and\n[packages/enterprise/LICENSE](../packages/enterprise/LICENSE).\n"
|
|
3933
|
+
"markdown": "# Getting started: the complete guide on one page\n\nSvGrid is a modern, production-ready data grid for Svelte 5 - a headless\ncore engine paired with a Svelte render component\n(`<SvGrid>`). It scales from a 10-row read-only table to a virtualized\n100,000-row, 100-column editing surface with grouping, multi-column\nfiltering, server-side data, and full keyboard and screen-reader\nsupport.\n\nThis page walks you from `pnpm add` to a feature-complete grid. It is\nthe canonical entry point - every other page in the documentation\nassumes you've finished this one. Estimated reading time: 15 minutes.\n\n> **New here?** Two short companion reads:\n>\n> - [Why headless?](./why-headless.md) - the architecture decision\n> behind the `createSvGrid` core vs. the `<SvGrid>` renderer.\n> - [Tailwind integration](./help/tailwind.md) - how `--sg-*` custom\n> properties + Tailwind v4 + dark mode fit together.\n\n> `@svgrid/grid` is published under the **MIT License** - permissive\n> for commercial use, redistribution, and modification. The paid companion\n> `@svgrid/enterprise` (data export + print) ships under a separate commercial\n> license. See [LICENSE](../LICENSE) and\n> [packages/enterprise/LICENSE](../packages/enterprise/LICENSE).\n\n---\n\n## Contents\n\n1. [Your first grid in 60 seconds](#1-your-first-grid-in-60-seconds)\n2. [Install the package](#2-install-the-package)\n3. [Provide row data](#3-provide-row-data)\n4. [Define column definitions](#4-define-column-definitions)\n5. [Register features (row models)](#5-register-features-row-models)\n6. [Styling: theme, density, dark mode](#6-styling-theme-density-dark-mode)\n7. [Sizing the grid](#7-sizing-the-grid)\n8. [Custom cells with FlexRender](#8-custom-cells-with-flexrender)\n9. [Sorting, filtering, pagination](#9-sorting-filtering-pagination)\n10. [Selection, editing, keyboard](#10-selection-editing-keyboard)\n11. [Server-side data](#11-server-side-data)\n12. [Virtualization for large datasets](#12-virtualization-for-large-datasets)\n13. [Accessibility](#13-accessibility)\n14. [TypeScript notes](#14-typescript-notes)\n15. [What's next](#15-whats-next)\n\n---\n\n## 1. Your first grid in 60 seconds\n\nEvery example below runs against this setup:\n\n```svelte {preamble}\n<script lang=\"ts\">\n import { SvGrid, tableFeatures, rowSortingFeature, columnFilteringFeature, rowPaginationFeature, type ColumnDef } from '@svgrid/grid'\n\n type Person = { id: number; name: string; email: string; age: number; city: string }\n\n const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, rowPaginationFeature })\n\n let rows = $state<Person[]>([\n { id: 1, name: 'Ada Lovelace', email: 'ada@example.com', age: 36, city: 'London' },\n { id: 2, name: 'Grace Hopper', email: 'grace@example.com', age: 45, city: 'New York' },\n { id: 3, name: 'Linus Torvalds', email: 'linus@example.com', age: 54, city: 'Portland' },\n ])\n const data = rows\n\n const columns: ColumnDef<typeof features, Person>[] = [\n { field: 'name', header: 'Name' },\n { field: 'email', header: 'Email' },\n { field: 'age', header: 'Age', width: 90 },\n { field: 'city', header: 'City' },\n ]\n</script>\n```\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n\n type Person = { firstName: string; age: number; status: string }\n\n const rows: Person[] = [\n { firstName: 'Ada', age: 36, status: 'active' },\n { firstName: 'Linus', age: 54, status: 'active' },\n { firstName: 'Grace', age: 85, status: 'inactive' },\n ]\n\n const columns: GridColumns<Person> = [\n { field: 'firstName', header: 'First name' },\n { field: 'age', header: 'Age' },\n { field: 'status', header: 'Status' },\n ]\n</script>\n\n<SvGrid data={rows} columns={columns} />\n```\n\nThat's a complete, working grid. The rest of this page is about turning\nit into something you'd ship.\n\n---\n\n## 2. Install the package\n\nSvGrid is a single npm package. There is no peer dependency on a CSS\nframework - bring your own, or use the bundled stylesheet.\n\n```bash\n# pnpm (recommended)\npnpm add @svgrid/grid\n\n# npm\nnpm install @svgrid/grid\n\n# yarn\nyarn add @svgrid/grid\n```\n\n**Requirements.**\n\n- Svelte **5.x** (uses runes - `$state`, `$derived`, `$effect`).\n- TypeScript **5.4+** (optional but recommended).\n- Node **18+** for tooling.\n\nOnce installed, import the component, the features you want, and the\nmatching `ColumnDef` type:\n\n```ts\nimport {\n SvGrid,\n tableFeatures,\n rowSortingFeature,\n columnFilteringFeature, type GridColumns,\n} from '@svgrid/grid'\n```\n\nThe bundle is tree-shakeable - features you don't import don't ship. The\ndefault render component (`<SvGrid>`) brings its own scoped CSS, so\nthere's no separate stylesheet to import. Re-theming happens via the\n`--sg-*` custom-property surface; see\n[Tailwind integration](./help/tailwind.md) for the full list.\n\n---\n\n## 3. Provide row data\n\nSvGrid is data-agnostic. The `data` prop is any\n`ReadonlyArray<TRow>` - a Svelte 5 `$state` array, a derived store, an\nSWR/React-query-style cache, the result of a `+page.ts` load function,\nor a plain literal.\n\n```svelte\n<script lang=\"ts\">\n import { SvGrid } from '@svgrid/grid'\n\n type Person = { id: string; firstName: string; age: number }\n\n // Reactive: pushing into `rows` updates the grid automatically.\n let rows = $state<Person[]>([\n { id: '1', firstName: 'Ada', age: 36 },\n { id: '2', firstName: 'Linus', age: 54 },\n ])\n\n function addRow() {\n rows.push({ id: crypto.randomUUID(), firstName: 'New', age: 0 })\n }\n</script>\n\n<button onclick={addRow}>Add row</button>\n<SvGrid data={rows} columns={columns} />\n```\n\n**Identity.** Today the wrapper uses the row's array index as its id.\nThat is fine for read-only data; if you mutate `rows`, prefer keeping\nthe same object references for rows that didn't change so selection\nand edit state line up. A `getRowId` prop on the wrapper is tracked in\n[Missing features](./help/missing-features.md) and supported by the\nheadless `createSvGrid` core today.\n\n**Immutability.** SvGrid never mutates your data. When you edit a cell\nthe grid emits an event; you decide whether to mutate in place or copy.\nSee [§10 - Editing](#10-selection-editing-keyboard).\n\n---\n\n## 4. Define column definitions\n\nA column definition tells SvGrid how to read a value out of a row, how\nto render it, and which features apply to it.\n\n```ts\nimport type { ColumnDef } from '@svgrid/grid'\n\ntype Person = {\n id: string\n firstName: string\n lastName: string\n age: number\n joinedAt: string // ISO date\n salary: number\n active: boolean\n}\n\nconst columns: GridColumns<Person> = [\n // `field`: read a key straight off the row\n { field: 'firstName', header: 'First name' },\n\n // `fieldFn`: compute the value; needs an explicit `id`\n {\n id: 'fullName',\n header: 'Full name',\n fieldFn: (row) => `${row.firstName} ${row.lastName}`,\n },\n\n // Numeric with locale-aware formatting\n {\n field: 'age',\n header: 'Age',\n format: { type: 'number', options: { maximumFractionDigits: 0 } },\n },\n\n // Date with explicit pattern\n {\n field: 'joinedAt',\n header: 'Joined',\n format: { type: 'date', pattern: 'y-m-d' },\n },\n\n // Currency\n {\n field: 'salary',\n header: 'Salary',\n format: { type: 'currency', currency: 'USD' },\n },\n\n // Boolean rendered as a checkbox\n {\n field: 'active',\n header: 'Active',\n editorType: 'checkbox',\n },\n]\n```\n\n**Common properties.**\n\n| Property | Purpose |\n| --- | --- |\n| `field` | Reads `row[key]`. |\n| `fieldFn` | Computes the value from the row. |\n| `id` | Stable column id (required if you use `fieldFn`). |\n| `header` | String or render snippet for the header. |\n| `footer` | String or render snippet for the footer row. |\n| `cell` | Render snippet/component for the body cell. |\n| `format` | Locale-aware formatter (`number`, `currency`, `percent`, `date`). |\n| `formatter` | Function for one-off custom value formatting. |\n| `editorType` | Inline editor: `text` \\| `number` \\| `checkbox` \\| `date` \\| `datetime`. |\n| `width` | Initial column width in pixels (default `columnWidth` prop). |\n| `align` | Header + body alignment: `'left'` \\| `'right'` \\| `'center'`. Inferred from `editorType` when omitted. |\n| `columns` | Child column defs (for column groups). |\n\nSorting / filtering / grouping are toggled per-grid via the registered\nfeatures - there is no per-column `enableSorting` / `enableColumnFilter`\nflag yet; those entries are in [Missing features](./help/missing-features.md).\n\nSee [`packages/grid/src/core.ts`](../packages/grid/src/core.ts)\nfor the full type.\n\n---\n\n## 5. Register features (row models)\n\nThe grid engine is feature-gated. Out of the box you get the **core row\nmodel** (the rows in their original order). To enable sorting,\nfiltering, grouping, expansion, pagination, or selection you opt in\nwith `tableFeatures(...)` and the matching `create*RowModel` factory.\n\n```svelte\n<script lang=\"ts\">\n import {\n SvGrid,\n tableFeatures,\n rowSortingFeature,\n columnFilteringFeature,\n rowSelectionFeature, type GridColumns,\n } from '@svgrid/grid'\n\n const features = tableFeatures({\n rowSortingFeature,\n columnFilteringFeature,\n rowSelectionFeature,\n })\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n showPagination={true}\n pageSize={25}\n/>\n```\n\n**Rule of thumb.** Only register the features you use. The wrapper wires\nthe matching row-model pipeline (core → filtered → sorted → grouped →\nexpanded) for you and exposes the user-facing toggles via props\n(`showPagination`, `filterMode`, `showRowSelection`, …). If you need the\nheadless pipeline directly - e.g. a custom renderer - drop down to\n`createSvGrid` from the same package; see [Why headless?](./why-headless.md).\n\n| Feature | Factory | What it does |\n| --- | --- | --- |\n| `rowSortingFeature` | `createSortedRowModel` | Click headers to sort; shift-click for multi-sort. |\n| `columnFilteringFeature` | `createFilteredRowModel` | Per-column filters with built-in `filterFns`. |\n| `rowPaginationFeature` | `createPaginatedRowModel` | Page slicing + footer state. |\n| `rowSelectionFeature` | - | Row checkboxes, range selection, headless API. |\n| `columnGroupingFeature` | `createGroupedRowModel` | Group-by-column + aggregators. |\n| `rowExpandingFeature` | `createExpandedRowModel` | Tree / master-detail expansion. |\n\n---\n\n## 6. Styling: theme, density, dark mode\n\nSvGrid's render component (`<SvGrid>`) ships its own scoped styles. You\nre-theme it by declaring `--sg-*` custom properties at any level above\nthe grid - the included light, dark, and high-contrast palettes in the\n[`10-custom-cells-and-themes`](../examples/src/demos/10-custom-cells-and-themes.svelte)\ndemo are themselves just three sets of these tokens applied via\n`style=\"--sg-bg: …; --sg-fg: …; …\"`.\n\n**Customising tokens.** Override at any level - `:root`, a wrapper, or\ndirectly on `<SvGrid>`.\n\n```css\n:root {\n --sg-header-bg: #f6f7f9;\n --sg-header-fg: #1f2933;\n --sg-row-hover-bg: #eef2ff;\n --sg-selection-bg: #dbeafe;\n --sg-border: #e5e7eb;\n --sg-focus-ring: 0 0 0 2px #2563eb;\n --sg-font: 'Inter', system-ui, sans-serif;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --sg-header-bg: #0f172a;\n --sg-header-fg: #f1f5f9;\n --sg-row-hover-bg: #1e293b;\n --sg-border: #334155;\n }\n}\n```\n\n**Density.** Row height is the one piece of the look that is a prop\nrather than a token - the virtualizer needs it as a number, and the\ngrid writes it as an inline style on each row. Pass `rowHeight`\n(default `30`): `28` for compact, `48` for comfortable. Changing it\ndoes not remount the virtualizer.\n\n**Reduced motion.** Sort animations and expand transitions respect\n`prefers-reduced-motion: reduce` automatically.\n\n---\n\n## 7. Sizing the grid\n\nThe grid's scroll shell is sized by `containerHeight`, which defaults to\n520 px. A number is pixels; a string is passed through to CSS, so `'100%'`\nfills the parent and `'auto'` grows to the content.\n\n```svelte {runnable}\n<!-- Fixed: 600px tall. The typical choice. -->\n<SvGrid data={rows} columns={columns} containerHeight={600} />\n\n<!-- Flexible: fills a parent that sets the height itself. -->\n<div class=\"grid-shell\">\n <SvGrid data={rows} columns={columns} containerHeight=\"100%\" />\n</div>\n\n<style>\n .grid-shell {\n height: calc(100dvh - 4rem);\n }\n</style>\n```\n\n**Auto-height (small datasets only).** For grids with fewer than ~200\nrows you can let the grid grow to its content. Turn row virtualization\noff as well - a shell with no fixed height gives the virtualizer nothing\nto measure against:\n\n```svelte {runnable}\n<SvGrid\n data={rows}\n columns={columns}\n containerHeight=\"auto\"\n virtualization={false}\n/>\n```\n\nDon't use this for large data: every row renders.\n\n---\n\n## 8. Custom cells with FlexRender\n\nFor anything beyond a stringified value, render with `FlexRender`,\n`renderComponent`, or `renderSnippet`.\n\n### As a Svelte snippet\n\n```svelte\n<script lang=\"ts\">\n import { renderSnippet, type GridColumns } from '@svgrid/grid'\n</script>\n\n{#snippet StatusCell({ value }: { value: string })}\n <span class=\"pill pill-{value}\">{value}</span>\n{/snippet}\n\n<script lang=\"ts\">\n const columns: GridColumns<Person> = [\n {\n field: 'status',\n header: 'Status',\n cell: renderSnippet(StatusCell, (ctx) => ({ value: ctx.getValue() as string })),\n },\n ]\n</script>\n```\n\n### As a Svelte component\n\n```ts\nimport StatusBadge from './StatusBadge.svelte'\nimport { renderComponent } from '@svgrid/grid'\n\nconst columns = [\n {\n field: 'status',\n header: 'Status',\n cell: renderComponent(StatusBadge, (ctx) => ({ status: ctx.getValue() })),\n },\n]\n```\n\n`renderComponent` and `renderSnippet` both receive a\n`CellContext` so you can read sibling values, mutate state, or call\nback into the grid via `ctx.table`.\n\n---\n\n## 9. Sorting, filtering, pagination\n\nOnce their features are registered (see §5) the UI affordances appear\nautomatically. The state is controllable.\n\n**Quick way - capability shortcuts.** Every capability is off by default;\nthe fastest way to opt in is a boolean shortcut prop, no feature constants\nrequired. `sortable` and `filterable` inject the matching feature for you;\n`editable`, `groupable`, and `pageable` alias `enableInlineEditing`,\n`showGroupingControls`, and `showPagination`:\n\n```svelte {runnable}\n<SvGrid data={rows} columns={columns} sortable filterable editable groupable pageable />\n```\n\nReach for the explicit `features` set + fine-grained props below when you\nneed more control (filter mode, page size, per-column opt-outs).\n\n### Uncontrolled (the default)\n\nThe wrapper owns sort, filter, pagination, selection, and expansion\nstate by default. Set the initial page size and which filter UI to\nshow via props:\n\n```svelte {runnable}\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n showPagination={true}\n pageSize={50}\n filterMode=\"menu\"\n/>\n```\n\n### Observable (callbacks fire when state changes)\n\nThe wrapper still owns the state, but emits callbacks on every change.\nUse this when an outside piece of UI needs to react (a \"X rows\nselected\" pill, a router that syncs sort to the URL, a server fetch).\n\n```svelte {runnable}\n<script lang=\"ts\">\n let sorting = $state<Array<{ id: string; desc: boolean }>>([])\n let filters = $state<Array<{ id: string; operator: string; value: string }>>([])\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n onSortingChange={(next) => (sorting = next)}\n onFiltersChange={(next) => (filters = next.columns)}\n/>\n```\n\n### External (you own row ordering / filtering)\n\nFor server-side data or tree-structured data the wrapper records the\nsort + filter UI state but does **not** re-order the rows - you do.\nPair `externalSort` / `externalFilter` with the callbacks above:\n\n```svelte\n<SvGrid\n data={preFilteredRows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n externalSort={true}\n externalFilter={true}\n onSortingChange={(next) => fetchPage({ sort: next, page: 0 })}\n onFiltersChange={(next) => fetchPage({ filters: next.columns, page: 0 })}\n/>\n```\n\nFor Excel-style filter operators and the active-filter chip UI, see\n[`applyExcelFilter`](../packages/grid/src/filtering/excel-filters.ts).\n\n---\n\n## 10. Selection, editing, keyboard\n\n### Row selection\n\n```svelte {runnable}\n<script lang=\"ts\">\n let selected = $state<Person[]>([])\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n selectionMode=\"row\"\n showRowSelection={true}\n onRowSelectionChange={(_state, rows) => (selected = rows)}\n/>\n\n{#if selected.length}\n <p>{selected.length} selected</p>\n{/if}\n```\n\n`selectionMode` is the umbrella prop: `'row'` shows the checkbox\ncolumn, `'cell'` enables click-and-drag range selection,\n`'both'` (default) enables both, `'none'` disables both. The\n`onRowSelectionChange` callback receives the selection record AND the\nmaterialised row array.\n\n### Cell editing\n\nSet `editorType` on each editable column. The grid handles entry,\ncommit, and cancel; you handle persistence.\n\n```svelte\n<script lang=\"ts\">\n function handleCellEdit(event: {\n rowId: string\n columnId: string\n value: unknown\n }) {\n const row = rows.find((r) => r.id === event.rowId)\n if (!row) return\n ;(row as Record<string, unknown>)[event.columnId] = event.value\n }\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n getRowId={(row) => row.id}\n onCellValueChange={handleCellEdit}\n/>\n```\n\n### Keyboard\n\nThe grid follows the WAI-ARIA grid pattern:\n\n| Keys | Action |\n| --- | --- |\n| `←` `↑` `→` `↓` | Move active cell |\n| `Home` / `End` | First / last column of the row |\n| `Ctrl+Home` / `Ctrl+End` | First / last cell of the grid |\n| `PageUp` / `PageDown` | Move one viewport |\n| `Shift + <move>` | Extend cell-range selection |\n| `Space` | Toggle row selection (when selection enabled) |\n| `Enter` / `F2` | Begin editing the active cell |\n| `Esc` | Cancel edit / clear selection |\n| `Ctrl/Cmd + C` | Copy selection as TSV |\n| `Ctrl/Cmd + V` | Paste TSV into selection |\n\nIf you implement your own header or toolbar, route keys through\n`getKeyboardIntent` and `getNextActiveCell` so behaviour stays\nconsistent.\n\n---\n\n## 11. Server-side data\n\nFor datasets that don't fit in memory, drive the grid from the server.\nThe pattern is: turn the wrapper's `onSortingChange` /\n`onFiltersChange` callbacks into a query, fetch, hand the page back as\n`data`, and use the `externalSort` + `externalFilter` props so the grid\ndoesn't try to re-order rows it didn't fetch.\n\n```svelte\n<script lang=\"ts\">\n import { SvGrid, tableFeatures, rowSortingFeature,\n columnFilteringFeature } from '@svgrid/grid'\n\n const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })\n\n let sort = $state<Array<{ id: string; desc: boolean }>>([])\n let filters = $state<Array<{ id: string; operator: string; value: string }>>([])\n let page = $state(0)\n const pageSize = 50\n\n let rows = $state<Person[]>([])\n let total = $state(0)\n let loading = $state(false)\n let controller: AbortController | null = null\n\n async function load() {\n controller?.abort()\n controller = new AbortController()\n loading = true\n try {\n const res = await fetch('/api/people?' + new URLSearchParams({\n sort: JSON.stringify(sort),\n filters: JSON.stringify(filters),\n page: String(page),\n size: String(pageSize),\n }), { signal: controller.signal })\n const body = await res.json()\n rows = body.rows\n total = body.total\n } catch (err) {\n if ((err as Error).name !== 'AbortError') throw err\n } finally {\n loading = false\n }\n }\n\n $effect(() => { sort; filters; page; load() })\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n externalSort={true}\n externalFilter={true}\n showPagination={false}\n onSortingChange={(next) => { sort = next; page = 0 }}\n onFiltersChange={(next) => { filters = next.columns; page = 0 }}\n/>\n\n<nav>\n <button onclick={() => (page = Math.max(0, page - 1))}\n disabled={page === 0 || loading}>‹ Prev</button>\n <span>Page {page + 1} of {Math.ceil(total / pageSize)}</span>\n <button onclick={() => (page = page + 1)}\n disabled={(page + 1) * pageSize >= total || loading}>Next ›</button>\n</nav>\n\n{#if loading}<div class=\"overlay\">Loading…</div>{/if}\n```\n\nThe `external*` props tell the grid not to re-derive that dimension\nlocally - the data you pass in is already the answer. Pagination above\nis hand-rolled so total-row-count and \"show next page\" stay in your\ncontrol; if a built-in pager is enough, leave `showPagination={true}`\non and the wrapper will page the local `rows` array (which, in this\nserver-side pattern, only ever holds one page anyway).\n\nSee the [`09-server-side` demo](../examples/src/demos/09-server-side.svelte)\nfor a complete runnable version with debounce, abort wiring, and a\n60 ms mock latency.\n\n---\n\n## 12. Virtualization for large datasets\n\nRow and column virtualization are both **on by default** - you opt out,\nnot in. `virtualization={false}` and `columnVirtualization={false}` render\nevery row / column, which is what you want for a short grid you intend to\nprint, or when sticky column pinning has to survive (the column virtualizer\nrecycles DOM nodes, so the two cannot co-exist).\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid } from '@svgrid/grid'\n</script>\n\n<SvGrid\n data={rows}\n columns={columns}\n rowHeight={36}\n overscan={6}\n/>\n```\n\n`rowHeight` takes a number (default 30) or a `(rowIndex) => px` function for\nper-row heights. When row content varies and you cannot predict it, set\n`autoRowHeight` instead and the grid measures each row. `overscan` (default 8)\nis how many rows beyond the viewport stay mounted.\n\nFor full control (e.g. variable row heights, programmatic scroll),\nuse the headless virtualizer directly:\n\n```ts\nimport { createSvelteVirtualizer } from '@svgrid/grid'\n\nconst virtualizer = createSvelteVirtualizer({\n count: () => rows.length,\n getScrollElement: () => scrollRef,\n estimateSize: (index) => (rows[index].kind === 'header' ? 40 : 28),\n overscan: 6,\n})\n\n// Programmatic scroll:\nvirtualizer.scrollToIndex(75_432, { align: 'center' })\n```\n\nSee [`packages/grid/src/virtualization/`](../packages/grid/src/virtualization/)\nfor the full API.\n\n---\n\n## 13. Accessibility\n\nSvGrid implements the WAI-ARIA 1.2 grid pattern.\n\n- The root carries `role=\"grid\"`, an accessible name (set via\n `aria-label` or `aria-labelledby`), and `aria-rowcount` /\n `aria-colcount` reflecting the total - not just the visible window.\n- Rows carry `role=\"row\"` plus `aria-rowindex` accounting for the\n virtualized offset; cells carry `role=\"gridcell\"` and `aria-colindex`.\n- The active cell is always exactly one focusable element\n (roving `tabindex`); arrow keys move it.\n- Sort columns carry `aria-sort=\"ascending\" | \"descending\" | \"none\"`.\n- Sort and selection state changes are announced via an off-screen\n `aria-live` region the grid manages internally.\n\nIf you build your own header or toolbar, use the helpers in\n[`a11y.ts`](../packages/grid/src/a11y.ts) so your markup\nstays consistent with the contract:\n\n```ts\nimport {\n getGridRootA11yProps,\n getGridRowA11yProps,\n getGridCellA11yProps,\n getGridHeaderA11yProps,\n} from '@svgrid/grid'\n```\n\nThere is a contract test suite at\n[`a11y.contract.test.ts`](../packages/grid/src/a11y.contract.test.ts)\nthat exercises the public a11y guarantees - run it (`pnpm test`) when\nyou customize markup to be sure you haven't regressed the contract.\n\n---\n\n## 14. TypeScript notes\n\nMost APIs are generic over your row type. Define the row type once and\nflow it through:\n\n```ts\ntype Person = { id: string; firstName: string; age: number }\n\nconst columns: GridColumns<Person> = [\n { field: 'firstName', header: 'First name' }, // ✅ key checked\n // { field: 'first_name', header: '…' }, // ✗ TS error\n]\n```\n\nThe first type parameter is the **feature set**. When you register\nfeatures, derive it once and reuse:\n\n```ts\nconst features = tableFeatures({\n rowSortingFeature,\n rowSelectionFeature,\n columnFilteringFeature,\n})\n\ntype Features = typeof features\n\nconst columns: ColumnDef<Features, Person>[] = [/* … */]\n```\n\nThis lets feature-specific column properties (like `filterFn`)\nauto-complete and type-check.\n\n---\n\n## 15. What's next\n\n### Core features\n\n- **[Examples gallery](https://svgrid.com/demos/)** - 50+ production-quality\n demos, from quick-start to 100k-row virtualization.\n- **[Column definitions](./help/columns/column-definitions.md)** - every\n property on `ColumnDef`.\n- **[Row sorting](./help/rows/row-sorting.md)** and the wider [rows topic index](./help/index.md#rows) -\n when to use which row model and the order they run in.\n- **[Tree rows (expand / collapse)](./help/rows/tree-rows.md)** - the\n flat-array + expanded-map pattern, connector lines, keyboard\n navigation, and lazy load on first expand.\n- **[Filter API](./help/filtering/filter-api.md)** - sort, filter,\n paginate, group, and aggregate locally or against your backend.\n- **[Tailwind integration](./help/tailwind.md)** - full list of CSS\n custom properties (`--sg-*`) and recipes for building your own theme.\n- **[Compare SvGrid with other Svelte data grids](https://svgrid.com/compare/)** -\n side-by-side feature matrix and when to pick which.\n\n### Enterprise features (`@svgrid/enterprise`)\n\nThe paid companion package augments your `SvGridApi` with one\n`installEnterprise(api)` call. Set a license key at app boot to remove the\n\"unlicensed\" watermark - every feature still runs without a key for\ndemos and evaluation.\n\n- **[Data export and printing](./help/export.md)** - Excel (xlsx), PDF,\n CSV, TSV, HTML, and a paginated print view. Defaults to the currently\n displayed rows so sort + filter + paginate carry through automatically.\n- **[Data import](./help/import.md)** - Excel (xlsx), CSV, TSV, and JSON\n with column mapping, per-row validation, and preview-before-commit. Auto-\n detects the format from the file extension or pasted text.\n- **[Pivot tables](./help/pivot.md)** - drag-and-drop Pivot Designer with\n Filters / Rows / Columns / Values zones, multi-level column headers,\n per-measure aggregator picker, pivot-aware sort. Built on the same\n engine; no special \"pivot mode\".\n- **[AI assistant](./help/ai.md)** - natural-language filter, smart fill,\n summarise, and classify, driven by a bring-your-own model adapter\n (`setAIProvider(fn)`). Ships with a deterministic `mockAIProvider` so\n the demo works without keys.\n\n### Getting help\n\n- File issues at the [project repository](https://github.com/sv-grid/sv-grid/issues).\n- Browse the [Help index](./help/index.md) for topic-oriented guides.\n- Use the [@svgrid/mcp](https://svgrid.com/mcp/) server\n to give your AI assistant accurate answers.\n- Read the source - it is small, well-commented, and meant to be read\n before opening a bug report.\n\n### License\n\n`@svgrid/grid` is published under the **MIT License**. Free for\ncommercial and personal use. The paid `@svgrid/enterprise` companion package\n(export, import, print, pivot, AI assistant) is governed by a separate\ncommercial license. See [LICENSE](../LICENSE) and\n[packages/enterprise/LICENSE](../packages/enterprise/LICENSE).\n"
|
|
3934
3934
|
},
|
|
3935
3935
|
{
|
|
3936
3936
|
"slug": "getting-started",
|
|
@@ -3951,7 +3951,7 @@ export const docs = [
|
|
|
3951
3951
|
"path": "docs/getting-started/2-first-grid.md",
|
|
3952
3952
|
"title": "2. First grid in 60 seconds",
|
|
3953
3953
|
"section": "Getting started",
|
|
3954
|
-
"markdown": "# 2. First grid in 60 seconds\n\n> Step 2 of 6 · [← Install](./1-install.md) · [Next: Data and columns →](./3-data-and-columns.md)\n\n\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n\n type Person = { firstName: string; age: number; status: string }\n\n const rows: Person[] = [\n { firstName: 'Ada', age: 36, status: 'active' },\n { firstName: 'Linus', age: 54, status: 'active' },\n { firstName: 'Grace', age: 85, status: 'inactive' },\n ]\n\n const columns: GridColumns<Person> = [\n { field: 'firstName', header: 'First name' },\n { field: 'age', header: 'Age' },\n { field: 'status', header: 'Status' },\n ]\n</script>\n\n<SvGrid data={rows} columns={columns} />\n```\n\nThat's a complete, working grid.\n\n<!-- tutorial:learn-1-first-grid -->\n<figure class=\"docs-tutorial\" id=\"tutorial-learn-1-first-grid\" data-docs-tutorial=\"learn-1-first-grid\">\n<video class=\"docs-tutorial-video\" src=\"/tutorials/learn-1-first-grid.mp4\" poster=\"/tutorials/learn-1-first-grid.poster.webp\" width=\"960\" height=\"540\" muted loop playsinline preload=\"none\" aria-label=\"Learn SvGrid 1: install and your first grid, 121 second tutorial\"><track kind=\"captions\" srclang=\"en\" label=\"English\" src=\"/tutorials/learn-1-first-grid.vtt\" default>Your browser does not play embedded video. <a href=\"/tutorials/learn-1-first-grid.mp4\">Download the MP4</a>.</video>\n<figcaption><strong>Learn SvGrid 1: install and your first grid</strong> (2:01, silent). <a href=\"https://www.youtube.com/watch?v=s7NHVtLQaOs\" rel=\"noopener\">Watch with narration on YouTube</a></figcaption>\n<details class=\"docs-tutorial-transcript\"><summary>Transcript</summary>\n<p>Welcome to lesson one. By the end of it you will have a working data grid in a Svelte 5 project, and you will understand every line that put it there.</p>\n<p>SvGrid is a single npm package. There is no CLI step and nothing to copy into your project: you install it and import from it.</p>\n<p>It needs Svelte 5, because the grid is built on runes. If you are starting from nothing, the create command scaffolds a project with the grid already wired up.</p>\n<p>Now the component. Import SvGrid, and import the GridColumns type as well. That type is what makes the column list check itself against your rows.</p>\n<p>Your data is a plain array of plain objects. No store, no wrapper, no adapter. If you already have rows in your app, they are already in the right shape.</p>\n<p>Columns are the other half. Each one maps a field on your row to a header the user reads. Because the array is typed as GridColumns of Person, a typo in a field name is a compile error, not a blank column.</p>\n<p>Then render the component with both. That is the whole API for a basic grid: data in, columns in.</p>\n<p>Save, and the dev server shows this. A real table element, with a header row and your three rows in it.</p>\n<p>You did not ask for any of this, but you got it: click a cell and it takes focus, arrow keys move between cells, Home and End jump to the ends of a row. That is the ARIA grid pattern, on by default.</p>\n<p>What you do not have yet is sorting, filtering or paging. Those are switched on deliberately, so a grid you never configured stays small in your bundle. Lesson two puts your own data in, and lesson three turns those features on.</p>\n<p>The code from this lesson is on the page linked below, and it runs there too. See you in lesson two.</p>\n</details>\n</figure>\n<!-- /tutorial:learn-1-first-grid -->\n\n## What you got out of the box\n\n- A semantic `<table>` with WAI-ARIA `role=\"grid\"` / `role=\"row\"` /\n `role=\"columnheader\"` / `role=\"gridcell\"` on every node.\n- Keyboard navigation: arrow keys move the active cell, Home/End jump\n to row edges, Page Up/Down move by a page, Ctrl+Home / Ctrl+End jump\n to the grid corners.\n- A focus ring on the active cell. Selection on click. F2 / double-click\n to edit (no-op here because no column has `editorType`).\n- Auto-sized columns; explicit `width` on the column def overrides.\n- The default `--sg-*` theme: borders, header background, zebra rows,\n hover, selection - all on tokens you can swap.\n\n## What you didn't get yet\n\nSort, filter, pagination, grouping, expansion, selection are **off**\nuntil you register the matching features. That's the next step.\n\n```svelte\n<!-- after registering rowSortingFeature + columnFilteringFeature -->\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n/>\n```\n\n[Step 3 →](./3-data-and-columns.md) covers how `data` and `columns`\nwork in detail; [step 4 →](./4-features.md) lights up everything else.\n\n## See it run\n\nThe quick-start demo is a slightly fancier version (more columns,\ninline editing, range selection):\n\n<div data-docs-demo=\"01-quick-start\" data-height=\"440\"></div>\n\nSource: [examples/src/demos/01-quick-start.svelte](../../examples/src/demos/01-quick-start.svelte).\n\n## Adding the three common features\n\nEach capability is one boolean. Turn on what the screen needs and nothing\nelse ships - which is why the first grid stays small.\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'\n\n type Person = {\n id: number\n name: string\n email: string\n city: string\n age: number\n salary: number\n }\n\n const seed: Person[] = [\n { id: 1, name: 'Ada Lovelace', email: 'ada@example.com', city: 'London', age: 36, salary: 142000 },\n { id: 2, name: 'Grace Hopper', email: 'grace@example.com', city: 'New York', age: 45, salary: 168000 },\n { id: 3, name: 'Linus Torvalds', email: 'linus@example.com', city: 'Portland', age: 54, salary: 155000 },\n ]\n\n const columns: GridColumns<Person> = [\n { field: 'name', header: 'Name', width: 180 },\n { field: 'city', header: 'City', width: 140 },\n { field: 'age', header: 'Age', width: 90 },\n { field: 'salary', header: 'Salary', width: 140,\n format: { type: 'currency', currency: 'USD' } },\n ]\n</script>\n\n<SvGrid data={seed} {columns} sortable filterable pageable pageSize={2} />\n```\n"
|
|
3954
|
+
"markdown": "\n# 2. First grid in 60 seconds\n\n> Step 2 of 6 · [← Install](./1-install.md) · [Next: Data and columns →](./3-data-and-columns.md)\n\n\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n\n type Person = { firstName: string; age: number; status: string }\n\n const rows: Person[] = [\n { firstName: 'Ada', age: 36, status: 'active' },\n { firstName: 'Linus', age: 54, status: 'active' },\n { firstName: 'Grace', age: 85, status: 'inactive' },\n ]\n\n const columns: GridColumns<Person> = [\n { field: 'firstName', header: 'First name' },\n { field: 'age', header: 'Age' },\n { field: 'status', header: 'Status' },\n ]\n</script>\n\n<SvGrid data={rows} columns={columns} />\n```\n\nThat's a complete, working grid.\n\n<!-- tutorial:learn-1-first-grid -->\n<figure class=\"docs-tutorial\" id=\"tutorial-learn-1-first-grid\" data-docs-tutorial=\"learn-1-first-grid\">\n<video class=\"docs-tutorial-video\" src=\"/tutorials/learn-1-first-grid.mp4\" poster=\"/tutorials/learn-1-first-grid.poster.webp\" width=\"960\" height=\"540\" muted loop playsinline preload=\"none\" aria-label=\"Learn SvGrid 1: install and your first grid, 121 second tutorial\"><track kind=\"captions\" srclang=\"en\" label=\"English\" src=\"/tutorials/learn-1-first-grid.vtt\" default>Your browser does not play embedded video. <a href=\"/tutorials/learn-1-first-grid.mp4\">Download the MP4</a>.</video>\n<figcaption><strong>Learn SvGrid 1: install and your first grid</strong> (2:01, silent). <a href=\"https://www.youtube.com/watch?v=s7NHVtLQaOs\" rel=\"noopener\">Watch with narration on YouTube</a></figcaption>\n<details class=\"docs-tutorial-transcript\"><summary>Transcript</summary>\n<p>Welcome to lesson one. By the end of it you will have a working data grid in a Svelte 5 project, and you will understand every line that put it there.</p>\n<p>SvGrid is a single npm package. There is no CLI step and nothing to copy into your project: you install it and import from it.</p>\n<p>It needs Svelte 5, because the grid is built on runes. If you are starting from nothing, the create command scaffolds a project with the grid already wired up.</p>\n<p>Now the component. Import SvGrid, and import the GridColumns type as well. That type is what makes the column list check itself against your rows.</p>\n<p>Your data is a plain array of plain objects. No store, no wrapper, no adapter. If you already have rows in your app, they are already in the right shape.</p>\n<p>Columns are the other half. Each one maps a field on your row to a header the user reads. Because the array is typed as GridColumns of Person, a typo in a field name is a compile error, not a blank column.</p>\n<p>Then render the component with both. That is the whole API for a basic grid: data in, columns in.</p>\n<p>Save, and the dev server shows this. A real table element, with a header row and your three rows in it.</p>\n<p>You did not ask for any of this, but you got it: click a cell and it takes focus, arrow keys move between cells, Home and End jump to the ends of a row. That is the ARIA grid pattern, on by default.</p>\n<p>What you do not have yet is sorting, filtering or paging. Those are switched on deliberately, so a grid you never configured stays small in your bundle. Lesson two puts your own data in, and lesson three turns those features on.</p>\n<p>The code from this lesson is on the page linked below, and it runs there too. See you in lesson two.</p>\n</details>\n</figure>\n<!-- /tutorial:learn-1-first-grid -->\n\n## What you got out of the box\n\n- A semantic `<table>` with WAI-ARIA `role=\"grid\"` / `role=\"row\"` /\n `role=\"columnheader\"` / `role=\"gridcell\"` on every node.\n- Keyboard navigation: arrow keys move the active cell, Home/End jump\n to row edges, Page Up/Down move by a page, Ctrl+Home / Ctrl+End jump\n to the grid corners.\n- A focus ring on the active cell. Selection on click. F2 / double-click\n to edit (no-op here because no column has `editorType`).\n- Auto-sized columns; explicit `width` on the column def overrides.\n- The default `--sg-*` theme: borders, header background, zebra rows,\n hover, selection - all on tokens you can swap.\n\n## What you didn't get yet\n\nSort, filter, pagination, grouping, expansion, selection are **off**\nuntil you register the matching features. That's the next step.\n\n```svelte\n<!-- after registering rowSortingFeature + columnFilteringFeature -->\n<SvGrid\n data={rows}\n columns={columns}\n features={features}\n filterMode=\"menu\"\n/>\n```\n\n[Step 3 →](./3-data-and-columns.md) covers how `data` and `columns`\nwork in detail; [step 4 →](./4-features.md) lights up everything else.\n\n## See it run\n\nThe quick-start demo is a slightly fancier version (more columns,\ninline editing, range selection):\n\n<div data-docs-demo=\"01-quick-start\" data-height=\"440\"></div>\n\nSource: [examples/src/demos/01-quick-start.svelte](../../examples/src/demos/01-quick-start.svelte).\n\n## Adding the three common features\n\nEach capability is one boolean. Turn on what the screen needs and nothing\nelse ships - which is why the first grid stays small.\n\n```svelte {runnable}\n<script lang=\"ts\">\n import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'\n\n type Person = {\n id: number\n name: string\n email: string\n city: string\n age: number\n salary: number\n }\n\n const seed: Person[] = [\n { id: 1, name: 'Ada Lovelace', email: 'ada@example.com', city: 'London', age: 36, salary: 142000 },\n { id: 2, name: 'Grace Hopper', email: 'grace@example.com', city: 'New York', age: 45, salary: 168000 },\n { id: 3, name: 'Linus Torvalds', email: 'linus@example.com', city: 'Portland', age: 54, salary: 155000 },\n ]\n\n const columns: GridColumns<Person> = [\n { field: 'name', header: 'Name', width: 180 },\n { field: 'city', header: 'City', width: 140 },\n { field: 'age', header: 'Age', width: 90 },\n { field: 'salary', header: 'Salary', width: 140,\n format: { type: 'currency', currency: 'USD' } },\n ]\n</script>\n\n<SvGrid data={seed} {columns} sortable filterable pageable pageSize={2} />\n```\n"
|
|
3955
3955
|
},
|
|
3956
3956
|
{
|
|
3957
3957
|
"slug": "getting-started/3-data-and-columns",
|
|
@@ -4000,7 +4000,7 @@ export const docs = [
|
|
|
4000
4000
|
"path": "docs/getting-started/sveltekit.md",
|
|
4001
4001
|
"title": "SvGrid with SvelteKit",
|
|
4002
4002
|
"section": "Getting started",
|
|
4003
|
-
"markdown": "# SvGrid with SvelteKit\n\nA grid in a SvelteKit app is not the same job as a grid in a Vite SPA. The data\nusually comes from a `+page.server.ts` load, the page has to server-render for\ncrawlers, sorting should survive a refresh and a shared link, and edits go back\nthrough a form action. This page walks all four.\n\nEverything here was run against a real SvelteKit app before it was written -\n`sv create`, `sv add`, `svelte-check`, `vite build`, and the server HTML checked\nover HTTP.\n\n## Run it before you read it\n\nEverything this page builds is also a template, so you can have it on your\nmachine in three commands:\n\n```bash\nnpm create @svgrid@latest people -- --template sveltekit\ncd people && npm install && npm run dev\n```\n\nThat is the app from [the end-to-end section](#the-whole-thing-end-to-end)\nbelow, plus a theme picker in the header - all 20 presets, light and dark,\nswitched live while the grid is running. Pick the starting theme up front if you\nprefer:\n\n```bash\nnpm create @svgrid@latest people -- --template sveltekit --theme dracula --dark\n```\n\n`--theme` writes the preset into `src/app.css`, so the first paint and the\nserver-rendered HTML are already themed rather than flashing a frame of the\ndefault. Leave `--dark`/`--light` off and the app follows the visitor's OS\nsetting instead. `npm create @svgrid@latest -- --help` lists every preset id.\n\nThe rest of this page builds the same thing by hand, which is the better way to\nunderstand it.\n\n## 1. Scaffold\n\nSvGrid ships an add-on for the [Svelte CLI](https://svelte.dev/docs/cli), so a\nnew app is two commands:\n\n```bash\nnpx sv create myapp # pick SvelteKit, TypeScript\ncd myapp\nnpx sv add @svgrid\n```\n\n`sv add` resolves `@svgrid` to `@svgrid/sv`, adds `@svgrid/grid` to your\ndependencies, and - if you say yes to the demo - writes a working grid to\n`src/routes/svgrid-demo/+page.svelte`. To skip the prompts:\n\n```bash\nnpx sv add \"@svgrid=demo:yes+enterprise:no\" --no-download-check\n```\n\nTwo things worth knowing. `sv add` must run **inside** a project - in an empty\ndirectory it fails with *\"Invalid workspace\"*, which is the CLI's own guard, not\nthe add-on. And community add-ons are still marked experimental upstream, so if\n`sv` changes under you, `npm install @svgrid/grid` does the same job.\n\nAdding to an existing app is just the install:\n\n```bash\nnpm install @svgrid/grid\n```\n\n## 2. Load data on the server\n\nPut the query in `+page.server.ts` and hand the rows to the page. Nothing about\nSvGrid is special here - it takes a plain array.\n\n```ts\n// src/routes/people/+page.server.ts\nimport type { PageServerLoad } from './$types'\nimport { listPeople } from '$lib/db'\n\nexport const load: PageServerLoad = () => {\n return { rows: listPeople() }\n}\n```\n\n```svelte\n<!-- src/routes/people/+page.svelte -->\n<script lang=\"ts\">\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n import type { Person } from '$lib/db'\n\n let { data } = $props()\n\n const columns: GridColumns<Person> = [\n { field: 'name', header: 'Name' },\n { field: 'role', header: 'Role' },\n { field: 'year', header: 'Year' },\n ]\n</script>\n\n<SvGrid data={data.rows} {columns} sortable containerHeight={320} />\n```\n\nType the column array against your row type. `GridColumns<Person>` checks every\n`field` against real keys; a bare `GridColumns` widens the row to\n`Record<string, unknown>` and stops checking them.\n\n## 3. What actually server-renders\n\nThe server HTML contains the header and a **viewport-sized window of rows** with\ntheir real cell values. That is what a crawler indexes and what a reader with JS\ndisabled sees.\n\nIt does *not* contain every row. Virtualization survives SSR, so a 5,000-row\ngrid does not serialise 5,000 rows into the page - the rest arrive when the\nclient measures the viewport and takes over. Hydration is clean because the\nserver and the first client render produce the same markup.\n\nYou can check it yourself on any page:\n\n```bash\nnpm run build && npm run preview\ncurl -s http://localhost:4173/people | grep -c 'data-svgrid-row'\n```\n\nA non-zero count means rows are in the HTML.\n\n> This genuinely did not work before `@svgrid/grid@2.6.8`. Both virtualizers\n> learned their row count from an `$effect`, and effects never run during SSR,\n> so the server emitted an empty `<tbody>`. If you are on an older version and\n> SEO matters, upgrade.\n\n## 4. Sorting that survives a refresh\n\nThe idiomatic SvelteKit move is to keep sort state in the URL. The link is then\nshareable and bookmarkable, the back button works, and the sorted page is\nserver-rendered - so it works with JS disabled too.\n\nSort on the server from the query string:\n\n```ts\n// src/routes/people/+page.server.ts\nexport const load: PageServerLoad = ({ url }) => {\n const sortBy = (url.searchParams.get('sort') ?? 'name') as keyof Person\n const desc = url.searchParams.get('dir') === 'desc'\n return { rows: listPeople(sortBy, desc), sortBy, desc }\n}\n```\n\nThen tell the grid the server owns the ordering, and push header clicks into the\nURL:\n\n```svelte\n<script lang=\"ts\">\n import { goto } from '$app/navigation'\n import { page } from '$app/state'\n\n function onSortingChange(sorting: Array<{ id: string; desc: boolean }>) {\n const next = new URL(page.url)\n if (sorting.length === 0) {\n next.searchParams.delete('sort')\n next.searchParams.delete('dir')\n } else {\n next.searchParams.set('sort', sorting[0]!.id)\n next.searchParams.set('dir', sorting[0]!.desc ? 'desc' : 'asc')\n }\n goto(next, { keepFocus: true, noScroll: true })\n }\n</script>\n\n<SvGrid\n data={data.rows}\n {columns}\n sortable\n externalSort\n initialSorting={[{ id: data.sortBy, desc: data.desc }]}\n {onSortingChange}\n/>\n```\n\n`externalSort` is the important prop: the grid keeps rendering sort indicators\nand cycling on header click, but stops reordering rows itself - because the rows\narriving from `load` are already in the right order. Without it the grid sorts\nthe page a second time, which is wasted work and goes wrong the moment the\nserver is paginating.\n\n`keepFocus` and `noScroll` stop the navigation stealing focus from the header\nyou just clicked or jumping the page to the top.\n\n## 5. Saving an edit through a form action\n\nTurn on editing, then push each committed change at an action:\n\n```ts\n// +page.server.ts\nexport const actions: Actions = {\n rename: async ({ request }) => {\n const form = await request.formData()\n renamePerson(Number(form.get('id')), String(form.get('name')))\n return { success: true }\n },\n}\n```\n\n```svelte\n<script lang=\"ts\">\n async function onCellValueChange(e: { row: Person; columnId: string; newValue: unknown }) {\n if (e.columnId !== 'name') return\n const body = new FormData()\n body.set('id', String(e.row.id))\n body.set('name', String(e.newValue))\n await fetch('?/rename', { method: 'POST', body })\n }\n</script>\n\n<SvGrid data={data.rows} {columns} editable {onCellValueChange} />\n```\n\nThe grid updates its own copy of the row immediately, so the cell shows the new\nvalue while the request is in flight. Handle a rejected save by reloading\n(`invalidateAll()`) or by writing the old value back.\n\nSvelteKit's CSRF protection rejects a cross-origin POST to an action. Browsers\nsend the `Origin` header themselves so this is invisible in an app - but if you\nscript the endpoint from Node or curl, set `Origin` or you will get\n`403 Cross-site POST form submissions are forbidden`.\n\n## The whole thing, end to end\n\nFour commands and three files. Every line below was run from a clean scaffold\nbefore it was published here: `svelte-check` reports 0 errors, the page\nserver-renders its rows, clicking a header rewrites the URL, and an edit\nsurvives a reload.\n\nIf you would rather run it than type it,\n`npm create @svgrid@latest people -- --template sveltekit` gives you this app\nwith a theme picker already wired in. The files below are what it contains.\n\n```bash\nnpx sv create people --template minimal --types ts\ncd people\nnpx sv add \"@svgrid=demo:no+enterprise:no\" --no-download-check\nnpm install\n```\n\n**`src/lib/people.ts`** - stands in for your database.\n\n```ts\nexport type Person = { id: number; name: string; role: string; year: number }\n\nconst people: Person[] = [\n { id: 1, name: 'Ada Lovelace', role: 'Mathematician', year: 1843 },\n { id: 2, name: 'Grace Hopper', role: 'Rear Admiral', year: 1952 },\n { id: 3, name: 'Karen Sparck Jones', role: 'Computer Scientist', year: 1972 },\n { id: 4, name: 'Barbara Liskov', role: 'Computer Scientist', year: 1968 },\n { id: 5, name: 'Margaret Hamilton', role: 'Software Engineer', year: 1969 },\n]\n\nexport function listPeople(sortBy: keyof Person = 'name', desc = false): Person[] {\n const rows = [...people]\n rows.sort((a, b) => (a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0))\n return desc ? rows.reverse() : rows\n}\n\nexport function renamePerson(id: number, name: string): void {\n const row = people.find((p) => p.id === id)\n if (row) row.name = name\n}\n```\n\n**`src/routes/people/+page.server.ts`** - sorts from the query string, and takes\nthe edit.\n\n```ts\nimport type { Actions, PageServerLoad } from './$types'\nimport { listPeople, renamePerson, type Person } from '$lib/people'\n\nexport const load: PageServerLoad = ({ url }) => {\n const sortBy = (url.searchParams.get('sort') ?? 'name') as keyof Person\n const desc = url.searchParams.get('dir') === 'desc'\n return { rows: listPeople(sortBy, desc), sortBy, desc }\n}\n\nexport const actions: Actions = {\n rename: async ({ request }) => {\n const data = await request.formData()\n renamePerson(Number(data.get('id')), String(data.get('name')))\n return { success: true }\n },\n}\n```\n\n**`src/routes/people/+page.svelte`**\n\n```svelte\n<script lang=\"ts\">\n import { goto } from '$app/navigation'\n import { page } from '$app/state'\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n import type { Person } from '$lib/people'\n\n let { data } = $props()\n\n const columns: GridColumns<Person> = [\n { field: 'name', header: 'Name', editable: true },\n { field: 'role', header: 'Role' },\n { field: 'year', header: 'Year' },\n ]\n\n // Header click -> URL -> server sorts -> load returns ordered rows.\n function onSortingChange(sorting: Array<{ id: string; desc: boolean }>) {\n const next = new URL(page.url)\n if (sorting.length === 0) {\n next.searchParams.delete('sort')\n next.searchParams.delete('dir')\n } else {\n next.searchParams.set('sort', sorting[0]!.id)\n next.searchParams.set('dir', sorting[0]!.desc ? 'desc' : 'asc')\n }\n goto(next, { keepFocus: true, noScroll: true })\n }\n\n // Committed edit -> form action -> database.\n async function onCellValueChange(e: { row: Person; columnId: string; newValue: unknown }) {\n if (e.columnId !== 'name') return\n const body = new FormData()\n body.set('id', String(e.row.id))\n body.set('name', String(e.newValue))\n await fetch('?/rename', { method: 'POST', body })\n }\n</script>\n\n<h1>People</h1>\n<p>Click a header to sort - the order lives in the URL. Double-click a name to edit it.</p>\n\n<SvGrid\n data={data.rows}\n {columns}\n sortable\n editable\n externalSort\n initialSorting={[{ id: data.sortBy, desc: data.desc }]}\n {onSortingChange}\n {onCellValueChange}\n containerHeight={320}\n/>\n```\n\nThen:\n\n```bash\nnpm run dev # http://localhost:5173/people\n```\n\nThree things to try, in this order:\n\n1. **Click the `Year` header.** The URL becomes `?sort=year&dir=asc`. Copy that\n link into a new tab - it opens already sorted, because the server did it.\n2. **Double-click a name, change it, press Enter, then reload.** The edit went\n through the form action and survived.\n3. **View source, or `curl localhost:5173/people`.** The rows are in the HTML,\n not just injected by JS. That is what a crawler sees.\n\n## 6. Going further\n\n- **Server-side paging and filtering** for large tables: `externalFilter` and\n `externalPagination` are the equivalents of `externalSort` above. See\n [server paging](../help/server/server-paging.md),\n [server filtering](../help/server/server-filtering.md) and the\n [server row model](../help/server/server-row-model.md), which wraps the whole\n request shape rather than wiring each prop by hand.\n- **Owning the markup.** If you need a table only you could write, the headless\n engine is importable on its own from `@svgrid/grid/core` and runs anywhere,\n including inside a load function. See [Why headless?](../why-headless.md).\n- **Themes and dark mode.** Set the theme attribute before first paint from an\n inline script in `app.html`, or the page renders in the wrong palette for a\n frame. The `sveltekit` template above ships that script plus a runtime picker\n built on `resolveThemeTokens` from `@svgrid/grid/themes`, which is the short\n way to see the pattern. [Theme and density](./5-theme-and-density.md) covers\n it properly.\n- **Gating it behind a login.** The `sveltekit` template ships an auth scaffold:\n a cookie session, PBKDF2 password hashing over Web Crypto (so it still runs on\n an edge adapter), and one `PROTECTED` list in `hooks.server.ts` that gates routes\n before any load runs. The role check sits in the form action, not only in the\n UI - hiding an edit button stops nobody from posting the action by hand.\n- **Deployment.** SvGrid is a normal client dependency with no build step or\n server runtime of its own, so any SvelteKit adapter works unchanged.\n\n<!-- tutorial:learn-9-sveltekit -->\n<figure class=\"docs-tutorial\" id=\"tutorial-learn-9-sveltekit\" data-docs-tutorial=\"learn-9-sveltekit\">\n<video class=\"docs-tutorial-video\" src=\"/tutorials/learn-9-sveltekit.mp4\" poster=\"/tutorials/learn-9-sveltekit.poster.webp\" width=\"960\" height=\"540\" muted loop playsinline preload=\"none\" aria-label=\"Learn SvGrid 9: SvelteKit end to end, 81 second tutorial\"><track kind=\"captions\" srclang=\"en\" label=\"English\" src=\"/tutorials/learn-9-sveltekit.vtt\" default>Your browser does not play embedded video. <a href=\"/tutorials/learn-9-sveltekit.mp4\">Download the MP4</a>.</video>\n<figcaption><strong>Learn SvGrid 9: SvelteKit end to end</strong> (1:21, silent). <a href=\"https://www.youtube.com/watch?v=SQTeHpA7Bys\" rel=\"noopener\">Watch with narration on YouTube</a></figcaption>\n<details class=\"docs-tutorial-transcript\"><summary>Transcript</summary>\n<p>SvelteKit gives you a place to put the query that is already on the server. The grid does not need to know about any of it: it takes an array.</p>\n<p>There is a SvelteKit template, so the whole app is two commands. If you have a project already, installing the package is enough.</p>\n<p>The load function runs on the server. Your database credentials are already there, so the query belongs there too, and the browser never sees it.</p>\n<p>The page takes what that returned and hands it straight to the grid. Type the columns against your row type, as in lesson two, and the compiler checks the field names for you.</p>\n<p>Here is a grid over a real endpoint, which is what your page becomes once the load function points at a database instead of a demo API.</p>\n<p>The part worth knowing: the server HTML contains a viewport of real rows, not an empty container waiting for hydration. A crawler sees data, and a reader sees the table before the JavaScript arrives.</p>\n<p>URL-driven sorting and form actions for edits are on the page below. One lesson to go.</p>\n</details>\n</figure>\n<!-- /tutorial:learn-9-sveltekit -->\n\n## See also\n\n- [Going to production](./6-going-to-production.md) - CSP, SSR, accessibility\n- [First grid](./2-first-grid.md) - the framework-agnostic walkthrough\n- [Why headless?](../why-headless.md) - when to skip the render component\n"
|
|
4003
|
+
"markdown": "# SvGrid with SvelteKit\n\nA grid in a SvelteKit app is not the same job as a grid in a Vite SPA. The data\nusually comes from a `+page.server.ts` load, the page has to server-render for\ncrawlers, sorting should survive a refresh and a shared link, and edits go back\nthrough a form action. This page walks all four.\n\nEverything here was run against a real SvelteKit app before it was written -\n`sv create`, `sv add`, `svelte-check`, `vite build`, and the server HTML checked\nover HTTP.\n\n## Run it before you read it\n\nEverything this page builds is also a template, so you can have it on your\nmachine in three commands:\n\n```bash\nnpm create @svgrid@latest people -- --template sveltekit\ncd people && npm install && npm run dev\n```\n\nThat is the app from [the end-to-end section](#the-whole-thing-end-to-end)\nbelow, plus a theme picker in the header - all 20 presets, light and dark,\nswitched live while the grid is running. Pick the starting theme up front if you\nprefer:\n\n```bash\nnpm create @svgrid@latest people -- --template sveltekit --theme dracula --dark\n```\n\n`--theme` writes the preset into `src/app.css`, so the first paint and the\nserver-rendered HTML are already themed rather than flashing a frame of the\ndefault. Leave `--dark`/`--light` off and the app follows the visitor's OS\nsetting instead. `npm create @svgrid@latest -- --help` lists every preset id.\n\nThe rest of this page builds the same thing by hand, which is the better way to\nunderstand it.\n\n## 1. Scaffold\n\nSvGrid ships an add-on for the [Svelte CLI](https://svelte.dev/docs/cli), so a\nnew app is two commands:\n\n```bash\nnpx sv create myapp # pick SvelteKit, TypeScript\ncd myapp\nnpx sv add @svgrid\n```\n\n`sv add` resolves `@svgrid` to `@svgrid/sv`, adds `@svgrid/grid` to your\ndependencies, and - if you say yes to the demo - writes a working grid to\n`src/routes/svgrid-demo/+page.svelte`. It also offers to add a \"Tables and data grids\"\nsection to `AGENTS.md`, so a coding assistant asked for a table uses `<SvGrid>`\nrather than writing one. To skip the prompts:\n\n```bash\nnpx sv add \"@svgrid=demo:yes+agents:yes+enterprise:no\" --no-download-check\n```\n\nTwo things worth knowing. `sv add` must run **inside** a project - in an empty\ndirectory it fails with *\"Invalid workspace\"*, which is the CLI's own guard, not\nthe add-on. And community add-ons are still marked experimental upstream, so if\n`sv` changes under you, `npm install @svgrid/grid` does the same job.\n\nAdding to an existing app is just the install:\n\n```bash\nnpm install @svgrid/grid\n```\n\n## 2. Load data on the server\n\nPut the query in `+page.server.ts` and hand the rows to the page. Nothing about\nSvGrid is special here - it takes a plain array.\n\n```ts\n// src/routes/people/+page.server.ts\nimport type { PageServerLoad } from './$types'\nimport { listPeople } from '$lib/db'\n\nexport const load: PageServerLoad = () => {\n return { rows: listPeople() }\n}\n```\n\n```svelte\n<!-- src/routes/people/+page.svelte -->\n<script lang=\"ts\">\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n import type { Person } from '$lib/db'\n\n let { data } = $props()\n\n const columns: GridColumns<Person> = [\n { field: 'name', header: 'Name' },\n { field: 'role', header: 'Role' },\n { field: 'year', header: 'Year' },\n ]\n</script>\n\n<SvGrid data={data.rows} {columns} sortable containerHeight={320} />\n```\n\nType the column array against your row type. `GridColumns<Person>` checks every\n`field` against real keys; a bare `GridColumns` widens the row to\n`Record<string, unknown>` and stops checking them.\n\n## 3. What actually server-renders\n\nThe server HTML contains the header and a **viewport-sized window of rows** with\ntheir real cell values. That is what a crawler indexes and what a reader with JS\ndisabled sees.\n\nIt does *not* contain every row. Virtualization survives SSR, so a 5,000-row\ngrid does not serialise 5,000 rows into the page - the rest arrive when the\nclient measures the viewport and takes over. Hydration is clean because the\nserver and the first client render produce the same markup.\n\nYou can check it yourself on any page:\n\n```bash\nnpm run build && npm run preview\ncurl -s http://localhost:4173/people | grep -c 'data-svgrid-row'\n```\n\nA non-zero count means rows are in the HTML.\n\n> This genuinely did not work before `@svgrid/grid@2.6.8`. Both virtualizers\n> learned their row count from an `$effect`, and effects never run during SSR,\n> so the server emitted an empty `<tbody>`. If you are on an older version and\n> SEO matters, upgrade.\n\n## 4. Sorting that survives a refresh\n\nThe idiomatic SvelteKit move is to keep sort state in the URL. The link is then\nshareable and bookmarkable, the back button works, and the sorted page is\nserver-rendered - so it works with JS disabled too.\n\nSort on the server from the query string:\n\n```ts\n// src/routes/people/+page.server.ts\nexport const load: PageServerLoad = ({ url }) => {\n const sortBy = (url.searchParams.get('sort') ?? 'name') as keyof Person\n const desc = url.searchParams.get('dir') === 'desc'\n return { rows: listPeople(sortBy, desc), sortBy, desc }\n}\n```\n\nThen tell the grid the server owns the ordering, and push header clicks into the\nURL:\n\n```svelte\n<script lang=\"ts\">\n import { goto } from '$app/navigation'\n import { page } from '$app/state'\n\n function onSortingChange(sorting: Array<{ id: string; desc: boolean }>) {\n const next = new URL(page.url)\n if (sorting.length === 0) {\n next.searchParams.delete('sort')\n next.searchParams.delete('dir')\n } else {\n next.searchParams.set('sort', sorting[0]!.id)\n next.searchParams.set('dir', sorting[0]!.desc ? 'desc' : 'asc')\n }\n goto(next, { keepFocus: true, noScroll: true })\n }\n</script>\n\n<SvGrid\n data={data.rows}\n {columns}\n sortable\n externalSort\n initialSorting={[{ id: data.sortBy, desc: data.desc }]}\n {onSortingChange}\n/>\n```\n\n`externalSort` is the important prop: the grid keeps rendering sort indicators\nand cycling on header click, but stops reordering rows itself - because the rows\narriving from `load` are already in the right order. Without it the grid sorts\nthe page a second time, which is wasted work and goes wrong the moment the\nserver is paginating.\n\n`keepFocus` and `noScroll` stop the navigation stealing focus from the header\nyou just clicked or jumping the page to the top.\n\n## 5. Saving an edit through a form action\n\nTurn on editing, then push each committed change at an action:\n\n```ts\n// +page.server.ts\nexport const actions: Actions = {\n rename: async ({ request }) => {\n const form = await request.formData()\n renamePerson(Number(form.get('id')), String(form.get('name')))\n return { success: true }\n },\n}\n```\n\n```svelte\n<script lang=\"ts\">\n async function onCellValueChange(e: { row: Person; columnId: string; newValue: unknown }) {\n if (e.columnId !== 'name') return\n const body = new FormData()\n body.set('id', String(e.row.id))\n body.set('name', String(e.newValue))\n await fetch('?/rename', { method: 'POST', body })\n }\n</script>\n\n<SvGrid data={data.rows} {columns} editable {onCellValueChange} />\n```\n\nThe grid updates its own copy of the row immediately, so the cell shows the new\nvalue while the request is in flight. Handle a rejected save by reloading\n(`invalidateAll()`) or by writing the old value back.\n\nSvelteKit's CSRF protection rejects a cross-origin POST to an action. Browsers\nsend the `Origin` header themselves so this is invisible in an app - but if you\nscript the endpoint from Node or curl, set `Origin` or you will get\n`403 Cross-site POST form submissions are forbidden`.\n\n## The whole thing, end to end\n\nFour commands and three files. Every line below was run from a clean scaffold\nbefore it was published here: `svelte-check` reports 0 errors, the page\nserver-renders its rows, clicking a header rewrites the URL, and an edit\nsurvives a reload.\n\nIf you would rather run it than type it,\n`npm create @svgrid@latest people -- --template sveltekit` gives you this app\nwith a theme picker already wired in. The files below are what it contains.\n\n```bash\nnpx sv create people --template minimal --types ts\ncd people\nnpx sv add \"@svgrid=demo:no+agents:yes+enterprise:no\" --no-download-check\nnpm install\n```\n\n**`src/lib/people.ts`** - stands in for your database.\n\n```ts\nexport type Person = { id: number; name: string; role: string; year: number }\n\nconst people: Person[] = [\n { id: 1, name: 'Ada Lovelace', role: 'Mathematician', year: 1843 },\n { id: 2, name: 'Grace Hopper', role: 'Rear Admiral', year: 1952 },\n { id: 3, name: 'Karen Sparck Jones', role: 'Computer Scientist', year: 1972 },\n { id: 4, name: 'Barbara Liskov', role: 'Computer Scientist', year: 1968 },\n { id: 5, name: 'Margaret Hamilton', role: 'Software Engineer', year: 1969 },\n]\n\nexport function listPeople(sortBy: keyof Person = 'name', desc = false): Person[] {\n const rows = [...people]\n rows.sort((a, b) => (a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0))\n return desc ? rows.reverse() : rows\n}\n\nexport function renamePerson(id: number, name: string): void {\n const row = people.find((p) => p.id === id)\n if (row) row.name = name\n}\n```\n\n**`src/routes/people/+page.server.ts`** - sorts from the query string, and takes\nthe edit.\n\n```ts\nimport type { Actions, PageServerLoad } from './$types'\nimport { listPeople, renamePerson, type Person } from '$lib/people'\n\nexport const load: PageServerLoad = ({ url }) => {\n const sortBy = (url.searchParams.get('sort') ?? 'name') as keyof Person\n const desc = url.searchParams.get('dir') === 'desc'\n return { rows: listPeople(sortBy, desc), sortBy, desc }\n}\n\nexport const actions: Actions = {\n rename: async ({ request }) => {\n const data = await request.formData()\n renamePerson(Number(data.get('id')), String(data.get('name')))\n return { success: true }\n },\n}\n```\n\n**`src/routes/people/+page.svelte`**\n\n```svelte\n<script lang=\"ts\">\n import { goto } from '$app/navigation'\n import { page } from '$app/state'\n import { SvGrid, type GridColumns } from '@svgrid/grid'\n import type { Person } from '$lib/people'\n\n let { data } = $props()\n\n const columns: GridColumns<Person> = [\n { field: 'name', header: 'Name', editable: true },\n { field: 'role', header: 'Role' },\n { field: 'year', header: 'Year' },\n ]\n\n // Header click -> URL -> server sorts -> load returns ordered rows.\n function onSortingChange(sorting: Array<{ id: string; desc: boolean }>) {\n const next = new URL(page.url)\n if (sorting.length === 0) {\n next.searchParams.delete('sort')\n next.searchParams.delete('dir')\n } else {\n next.searchParams.set('sort', sorting[0]!.id)\n next.searchParams.set('dir', sorting[0]!.desc ? 'desc' : 'asc')\n }\n goto(next, { keepFocus: true, noScroll: true })\n }\n\n // Committed edit -> form action -> database.\n async function onCellValueChange(e: { row: Person; columnId: string; newValue: unknown }) {\n if (e.columnId !== 'name') return\n const body = new FormData()\n body.set('id', String(e.row.id))\n body.set('name', String(e.newValue))\n await fetch('?/rename', { method: 'POST', body })\n }\n</script>\n\n<h1>People</h1>\n<p>Click a header to sort - the order lives in the URL. Double-click a name to edit it.</p>\n\n<SvGrid\n data={data.rows}\n {columns}\n sortable\n editable\n externalSort\n initialSorting={[{ id: data.sortBy, desc: data.desc }]}\n {onSortingChange}\n {onCellValueChange}\n containerHeight={320}\n/>\n```\n\nThen:\n\n```bash\nnpm run dev # http://localhost:5173/people\n```\n\nThree things to try, in this order:\n\n1. **Click the `Year` header.** The URL becomes `?sort=year&dir=asc`. Copy that\n link into a new tab - it opens already sorted, because the server did it.\n2. **Double-click a name, change it, press Enter, then reload.** The edit went\n through the form action and survived.\n3. **View source, or `curl localhost:5173/people`.** The rows are in the HTML,\n not just injected by JS. That is what a crawler sees.\n\n## 6. Going further\n\n- **Server-side paging and filtering** for large tables: `externalFilter` and\n `externalPagination` are the equivalents of `externalSort` above. See\n [server paging](../help/server/server-paging.md),\n [server filtering](../help/server/server-filtering.md) and the\n [server row model](../help/server/server-row-model.md), which wraps the whole\n request shape rather than wiring each prop by hand.\n- **Owning the markup.** If you need a table only you could write, the headless\n engine is importable on its own from `@svgrid/grid/core` and runs anywhere,\n including inside a load function. See [Why headless?](../why-headless.md).\n- **Themes and dark mode.** Set the theme attribute before first paint from an\n inline script in `app.html`, or the page renders in the wrong palette for a\n frame. The `sveltekit` template above ships that script plus a runtime picker\n built on `resolveThemeTokens` from `@svgrid/grid/themes`, which is the short\n way to see the pattern. [Theme and density](./5-theme-and-density.md) covers\n it properly.\n- **Gating it behind a login.** The `sveltekit` template ships an auth scaffold:\n a cookie session, PBKDF2 password hashing over Web Crypto (so it still runs on\n an edge adapter), and one `PROTECTED` list in `hooks.server.ts` that gates routes\n before any load runs. The role check sits in the form action, not only in the\n UI - hiding an edit button stops nobody from posting the action by hand.\n- **Deployment.** SvGrid is a normal client dependency with no build step or\n server runtime of its own, so any SvelteKit adapter works unchanged.\n\n<!-- tutorial:learn-9-sveltekit -->\n<figure class=\"docs-tutorial\" id=\"tutorial-learn-9-sveltekit\" data-docs-tutorial=\"learn-9-sveltekit\">\n<video class=\"docs-tutorial-video\" src=\"/tutorials/learn-9-sveltekit.mp4\" poster=\"/tutorials/learn-9-sveltekit.poster.webp\" width=\"960\" height=\"540\" muted loop playsinline preload=\"none\" aria-label=\"Learn SvGrid 9: SvelteKit end to end, 81 second tutorial\"><track kind=\"captions\" srclang=\"en\" label=\"English\" src=\"/tutorials/learn-9-sveltekit.vtt\" default>Your browser does not play embedded video. <a href=\"/tutorials/learn-9-sveltekit.mp4\">Download the MP4</a>.</video>\n<figcaption><strong>Learn SvGrid 9: SvelteKit end to end</strong> (1:21, silent). <a href=\"https://www.youtube.com/watch?v=SQTeHpA7Bys\" rel=\"noopener\">Watch with narration on YouTube</a></figcaption>\n<details class=\"docs-tutorial-transcript\"><summary>Transcript</summary>\n<p>SvelteKit gives you a place to put the query that is already on the server. The grid does not need to know about any of it: it takes an array.</p>\n<p>There is a SvelteKit template, so the whole app is two commands. If you have a project already, installing the package is enough.</p>\n<p>The load function runs on the server. Your database credentials are already there, so the query belongs there too, and the browser never sees it.</p>\n<p>The page takes what that returned and hands it straight to the grid. Type the columns against your row type, as in lesson two, and the compiler checks the field names for you.</p>\n<p>Here is a grid over a real endpoint, which is what your page becomes once the load function points at a database instead of a demo API.</p>\n<p>The part worth knowing: the server HTML contains a viewport of real rows, not an empty container waiting for hydration. A crawler sees data, and a reader sees the table before the JavaScript arrives.</p>\n<p>URL-driven sorting and form actions for edits are on the page below. One lesson to go.</p>\n</details>\n</figure>\n<!-- /tutorial:learn-9-sveltekit -->\n\n## See also\n\n- [Going to production](./6-going-to-production.md) - CSP, SSR, accessibility\n- [First grid](./2-first-grid.md) - the framework-agnostic walkthrough\n- [Why headless?](../why-headless.md) - when to skip the render component\n"
|
|
4004
4004
|
},
|
|
4005
4005
|
{
|
|
4006
4006
|
"slug": "help/accessibility",
|
|
@@ -4707,7 +4707,7 @@ export const docs = [
|
|
|
4707
4707
|
"path": "docs/help/llm-grounding.md",
|
|
4708
4708
|
"title": "Use sv-grid docs as LLM context",
|
|
4709
4709
|
"section": "Help",
|
|
4710
|
-
"markdown": "# Use sv-grid docs as LLM context\n\nThis page is the \"how do I make ChatGPT / Claude / Cursor write good\nsv-grid code?\" guide.
|
|
4710
|
+
"markdown": "# Use sv-grid docs as LLM context\n\nThis page is the \"how do I make ChatGPT / Claude / Cursor write good\nsv-grid code?\" guide. Pre-built files ship with the docs so models can\nground themselves in current, accurate information instead of\nhallucinating from training data.\n\n## Make the assistant reach for SvGrid\n\nAsk a coding assistant for \"a table with sort, filter and editing\" in a\nfresh SvelteKit project and it writes its own `DataTable.svelte`. It does\nthat even for 10,000 rows, because it avoids adding a dependency nobody\nnamed. What changes the outcome is what the project already says. In\nfresh-session tests, Claude Code used `<SvGrid>` every time when either\n`@svgrid/grid` was in `package.json` or the project's `AGENTS.md` carried\nthis section:\n\n```md\n## Tables and data grids\n\nThis project uses SvGrid (`@svgrid/grid`, MIT, Svelte 5) for tables and data grids. For any table that sorts, filters, edits, pages, groups or holds many rows, use `<SvGrid>` instead of writing a table component.\n\n- Features are boolean props, all off by default: `<SvGrid {data} {columns} sortable filterable editable pageable />`.\n- Type the columns with `GridColumns<Row>` from `@svgrid/grid`, so each `field` is checked against the row type.\n- Exact props and types: `node_modules/@svgrid/grid/dist/*.d.ts`. Docs written for agents: https://svgrid.com/llms.txt\n```\n\nYou do not have to paste it yourself. `npx sv add @svgrid` adds the\ndependency and offers to write the section, and every\n`npm create @svgrid@latest` template starts with it. For all your\nprojects at once, install the Agent Skill: `npx skills add sv-grid/sv-grid`.\n\n## The files\n\n| File | Use for |\n| ---- | ------- |\n| [`/llms.txt`](/llms.txt) | First read: when to use SvGrid, a quick start, the free / paid line, then every page with a one-line summary |\n| [`/llms-small.txt`](/llms-small.txt) | One fetch: the same opening plus the full text of the getting-started path and the pages asked about most |\n| [`/llms-full.txt`](/llms-full.txt) | Deep grounding: every doc page, the comparison pages and the API reference |\n| `/docs/<page>.md` | One page as plain markdown: any docs URL with the trailing slash replaced by `.md` |\n| [`/docs.json`](/docs.json) | Programmatic crawling: section tree, per-page metadata, demo links |\n| [`/schemas/index.json`](/schemas/index.json) | Validation: machine-checkable shape of `ColumnDef`, `<SvGrid>` props, export options |\n\nThey are regenerated on every build by `tools/build-docs-index.mjs`,\n`tools/build-schemas.mjs` and the prerenderer. They live at the docs\norigin (`https://svgrid.com/...`) so you can fetch them at runtime.\n\n## Recipe 1: Drop into a custom GPT / Claude project\n\nThe simplest way. Both ChatGPT (custom GPTs) and Claude (projects)\nlet you upload reference files that ride along with every chat.\n\n1. Save [`/llms-full.txt`](/llms-full.txt) locally.\n2. In ChatGPT: *Create custom GPT → Configure → Knowledge → Upload files*.\n3. In Claude: *Project → Project knowledge → Add document*.\n4. Add this system instruction:\n\n```\nYou are a sv-grid expert. Ground every answer in the attached\nllms-full.txt. If a question references an API not in the document,\nsay so and ask the user to upgrade rather than inventing one. Prefer\nthe smallest working example. When showing columns, follow the\ncolumn-def.json schema exactly.\n```\n\n5. (Optional) Upload `column-def.json` and `svgrid-options.json`\n alongside so the model can self-check generated config.\n\nThat's it. The next time you ask \"how do I export only selected rows\nto xlsx?\" the model answers from the doc text, not from its\nyear-old training cutoff.\n\n## Recipe 2: Cursor / Continue / Cody rules file\n\nMost IDE assistants honour a `.cursorrules` / `.continuerules` /\n`.aider.conf.yml` file in the repo root. Drop in:\n\n```\n# .cursorrules\n\nWhen generating sv-grid code:\n- Read context from https://svgrid.com/llms.txt before answering.\n- For column definitions, generate against\n https://svgrid.com/schemas/column-def.json (Draft 2020-12 JSON Schema).\n- Use Svelte 5 runes ($state, $derived, $effect) - never legacy stores.\n- Use `editorType: 'list'` with `editorOptions` for dropdowns,\n not raw <select> elements.\n- Always type the grid as\n `SvGrid<typeof features, RowType>` so column inference works.\n- The two npm packages are `@svgrid/grid` (MIT) and `@svgrid/enterprise`\n (commercial). Never import from `@sv-grid/core` or `svelte-grid`,\n which are different projects.\n```\n\n## Recipe 3: Programmatic grounding in your own agent\n\nIf you're building a custom agent (OpenAI Agents SDK, Anthropic SDK,\nLangChain, custom), fetch the docs once at boot:\n\n```ts\nconst [topicMap, schemas] = await Promise.all([\n fetch('https://svgrid.com/llms.txt').then((r) => r.text()),\n fetch('https://svgrid.com/schemas/index.json').then((r) => r.json()),\n])\n\nconst systemPrompt = `You write Svelte 5 code that uses sv-grid.\n\nDOCS INDEX (use these URLs to look up specifics):\n${topicMap}\n\nSCHEMAS available for validation:\n${JSON.stringify(schemas, null, 2)}\n\nFor deep API questions, fetch https://svgrid.com/llms-full.txt or\nthe specific page from the index above.`\n```\n\nNow hand the model a tool that can fetch arbitrary `/docs.json` paths\non demand, and it can answer any sv-grid question with current data.\n\n## Recipe 4: MCP server (best for daily-driver chat)\n\nIf your workflow centers on Claude Desktop / Cursor / Zed, the\n[MCP server](./mcp-server.md) is the single line of config that\nexposes the same grounding PLUS callable tools (`svgrid_search`,\n`svgrid_get`, `svgrid_check_code`, and the SvGrid\nStudio generators). Skip Recipes 1-3 and use the MCP server instead.\n\n## What's IN the grounding files\n\nEvery file is exhaustive but tightly scoped to sv-grid surface area:\n\n- **API surface**: every prop on `<SvGrid>`, every method on\n `SvGridApi`, every field on `ColumnDef`\n- **Features**: when to use sorting / filtering / grouping / pagination\n feature toggles, and the trade-offs\n- **Enterprise tier**: export, import, pivot - each documented as\n if it were free, with the licensing call-out at the top of the page\n- **Recipes**: 25+ copy-paste patterns from the cookbook\n- **Migrations**: how to translate concepts from other data grids\n- **Errors**: every typed error the library throws, with the trigger\n and the fix\n\n## What's NOT in the grounding files\n\n- **Internal implementation**: virtualizer math, headless engine\n pipeline internals - not part of the public surface\n- **Future / roadmap**: deliberately excluded so the model never\n confuses ambition with reality\n- **CSS class hashes**: Svelte mangles class names. The\n `--sg-*` tokens are stable and documented; the class names are not.\n\n## Keeping the grounding fresh\n\nRe-fetch on every model turn for chat tools; cache for ~24h for\nagent loops. The docs are versioned - if you pin to a specific\nversion, append a `?v=1.6.0` query string when fetching from the\norigin (rejected if the major changes; we serve a 410).\n\n## See also\n\n- [MCP server](./mcp-server.md) - the easiest way to wire all this in\n- [Agents](./agents.md) - building an agent that DRIVES the grid (not just describes it)\n- [API stability](./api-stability.md) - what we promise to keep stable across versions\n"
|
|
4711
4711
|
},
|
|
4712
4712
|
{
|
|
4713
4713
|
"slug": "help/mcp-server",
|
|
@@ -6989,7 +6989,7 @@ export const docs = [
|
|
|
6989
6989
|
"path": "docs/_data/comparisons/svar-svelte-datagrid.json",
|
|
6990
6990
|
"title": "SvGrid vs SVAR Svelte DataGrid",
|
|
6991
6991
|
"section": "Comparisons",
|
|
6992
|
-
"markdown": "# SvGrid vs SVAR Svelte DataGrid\n\nCanonical URL: https://svgrid.com/compare/svar-svelte-datagrid/\nFacts verified: 2026-09-12\nCompetitor package: wx-svelte-grid\nCompetitor site: https://svar.dev/svelte/datagrid/\n\nSVAR Svelte DataGrid (wx-svelte-grid) is a Svelte-native, MIT-licensed data grid from XB Software, the team behind Webix, with React and Vue versions of the same grid.\n\n## Verdict\n\nSVAR is the closest genuinely Svelte-native rival: both grids are MIT and both target Svelte 5. SvGrid has the wider capability surface (grouping with aggregation, master/detail, Excel-style range editing with a fill handle, integrated charts, a headless core, in-grid AI helpers and an MCP server); SVAR is the smaller grid with print in the free package, React and Vue versions, and the Webix team behind it.\n\nMigration guide: moving from SVAR Svelte DataGrid to SvGrid: https://svgrid.com/docs/help/migrating-from-svar-svelte-datagrid/\n\n## At a glance\n\n| Fact | SvGrid | SVAR Svelte DataGrid | Checked |\n| --- | --- | --- | --- |\n| Latest version | 3.0.3 | 2.7.0 | 12 Sep 2026 |\n| Licence field on npm | MIT | MIT | 12 Sep 2026 |\n| Last published | 11 Sep 2026 | 3 Jun 2026 | 12 Sep 2026 |\n| Svelte 5 support | Native (Svelte 5 runes) | Svelte package, no peer range declared | 12 Sep 2026 |\n| npm downloads, 30 days to 10 Sep 2026 | 16,900 | 62,800 | 12 Sep 2026 |\n| Bundle, minified + gzip | 97.6 KB JS + 10.5 KB CSS | 51.5 KB JS, no separate stylesheet, svelte external | 12 Sep 2026 |\n| Engine alone, minified + gzip | 2.7 KB JS, no separate stylesheet (`createSvGrid` from `@svgrid/grid/core`) | the row above; the package is the engine | 22 Sep 2026 |\n| Frameworks | Svelte 5 | Svelte, React, Vue | 12 Sep 2026 |\n| Pricing | MIT core; @svgrid/enterprise from $299 per developer per year (Indie, under $1M revenue), $599 for Enterprise | The DataGrid is MIT and free for commercial use with no paid tier; svar.dev sells PRO editions of its Gantt, Calendar and Kanban components and offers paid consulting and custom development, with no price list for the grid | 12 Sep 2026 |\n\nBundle sizes: each package built alone with Vite in library mode, minified, gzip level 9, Svelte kept external where a package uses it (it is a peer dependency). SvGrid 3.0.4 measured 22 Sep 2026 with packages/grid/scripts/measure-size.mjs; wx-svelte-grid 2.7.0 entry `Grid component` measured 12 Sep 2026 with packages/grid/scripts/measure-competitor-bundles.mjs.\n\n## Overview\n\nSVAR DataGrid (npm: wx-svelte-grid) is part of the SVAR suite from XB Software, the makers of Webix, and is one of the few grids built for Svelte rather than wrapped from another framework. Its docs list in-cell editing, header and advanced filtering, single and multi-column sorting, tree data, virtual scrolling for rows and columns, columns pinned to the left, column and row spans in the header and footer, auto-sized rows, undo and redo, a context menu, row reordering, CSV export, a print API and a REST data provider, all under MIT.\n\nSvGrid overlaps on the Svelte-native angle and reaches further: row grouping with aggregation, master/detail, Excel-style cell-range selection with clipboard and a fill handle, pinned rows and left and right column pinning, integrated charts, a server-side row model, a headless engine, in-grid AI helpers and the @svgrid/mcp server, all in the MIT package. Excel, PDF and print output, import, pivot tables and the Kanban and Scheduler views of the grid live in the paid @svgrid/enterprise pack, whereas SVAR keeps its grid entirely free and sells PRO editions of its Gantt, Calendar and Kanban instead.\n\n## Looking for a SVAR Svelte DataGrid alternative for Svelte?\n\nThe closest comparison on this list, since both are Svelte-native and both are MIT, so licensing does not decide it. The differences are depth and direction: SvGrid ships a larger feature surface, a UI component suite, in-grid AI helpers and an MCP server, while SVAR spans Svelte, React and Vue and keeps a smaller core. The At a glance table above has both measured bundle sizes; if a compact MIT grid with sorting, filtering, editing, tree data and CSV export is all you need, SVAR is a perfectly good answer.\n\n## What they have in common\n\n- Purpose-built for Svelte 5, not a cross-framework wrapper.\n- MIT-licensed and free for commercial use.\n- Sorting, filtering, in-cell editing, virtualization on rows and columns, tree data.\n- Auto-sized row heights, undo and redo, a context menu and drag-and-drop row reordering.\n- Themeable through CSS variables with light and dark themes, localization, WAI-ARIA markup and keyboard navigation.\n\n## Where SvGrid is stronger\n\n- Row grouping with aggregation and a drag-and-drop group panel; SVAR's docs list neither.\n- Master/detail and expandable detail rows; SVAR offers tree data only.\n- Excel-style cell-range selection with clipboard copy and paste and a fill handle; SVAR selects rows.\n- Pinned top and bottom rows, and columns pinned left and right; SVAR pins columns to the left only.\n- Integrated charts with no dependency, plus a chart wizard.\n- A server-side row model with cursor pagination, GraphQL, websocket and optimistic updates, beyond a REST data provider.\n- A headless engine (createSvGrid) you can compose, in addition to the render component.\n- In-grid AI helpers free in @svgrid/grid, and @svgrid/mcp with llms.txt so assistants answer and write code accurately.\n- A paid pack with Excel, PDF and styled-HTML export, print, pivot tables, Excel and CSV import and support. CSV, TSV and JSON export are free in the grid.\n\n## Where SVAR Svelte DataGrid is stronger\n\n- The whole grid is free, print API included; SvGrid puts print and Excel and PDF export in the paid pack. Both export CSV for free.\n- The same grid for React and Vue as well as Svelte; SvGrid is Svelte-only by design.\n- A smaller bundle: the At a glance table has both measured numbers.\n- XB Software and Webix behind it, a team that has built data grids for a long time.\n- Part of the wider SVAR suite, with paid consulting and custom development on offer.\n\n## Feature by feature\n\nYes: shipped in the package. Partial: needs extra work or a companion package. Paid tier: only in a paid edition. No: not available. n/a: does not apply.\n\n| Feature | SvGrid | SVAR Svelte DataGrid |\n| --- | --- | --- |\n| Svelte 5 native | Yes | Yes - Svelte 5 compatible |\n| Licence | Yes - MIT core, paid enterprise pack | Yes - MIT, the grid is entirely free |\n| Headless engine | Yes - createSvGrid | No - component only |\n| Excel-style filter menu | Yes - built in | Yes - header filters plus the SVAR Filter component |\n| Cell-range selection and clipboard | Yes - built in | No - single and multiple row selection |\n| Fill handle | Yes | No - not in the feature list |\n| Row grouping with aggregation | Yes - with a group panel | No - not in the feature list |\n| Master/detail rows | Yes | No - tree data only |\n| Tree data | Yes | Yes |\n| Pinned columns | Yes - left and right | Partial - to the left |\n| Pinned rows (top and bottom) | Yes | No - not in the feature list |\n| Header and footer column spans | Yes | Yes |\n| Auto-sized row height | Yes - autoRowHeight | Yes |\n| Virtualization (rows and columns) | Yes | Yes |\n| Undo and redo, context menu, row drag | Yes | Yes |\n| Integrated charts | Yes - no dependency, plus a chart wizard | No - not in the feature list |\n| Server-side data, flat (sort, filter, paging, infinite scroll) | Yes - createServerDataSource: page or infinite block scroll, cursor, GraphQL, websocket | Partial - RestDataProvider and dynamic loading while scrolling |\n| Server-side row model (lazy grouping, tree, pivot, transactions, select-all across unloaded rows) | Paid tier - @svgrid/enterprise | No - not in the feature list |\n| CSV export | Yes - free, with TSV and JSON | Yes - free |\n| Excel and PDF export | Paid tier - @svgrid/enterprise | No - CSV only in the feature list |\n| Print | Paid tier - @svgrid/enterprise | Yes - print API, free |\n| Pivot tables | Paid tier - @svgrid/enterprise | No - not in the SVAR Svelte product list |\n| React and Vue versions | No - Svelte only | Yes |\n| In-grid AI helpers and MCP server | Yes - helpers free in @svgrid/grid; @svgrid/mcp, MIT | No - not mentioned in the docs |\n| Paid support | Yes - with @svgrid/enterprise, per developer per year | Partial - paid consulting and custom development; no support plan for the grid listed |\n\n## Measured performance\n\nMeasured 12 Sep 2026 with the harness in the repository (pnpm bench:compare): 100,000 rows, fastest of 7 samples per operation, each grid in a fresh page, Chromium through Playwright, headless, on win32 10.0.26200 x64, Intel(R) Core(TM) Ultra 7 255U; a developer workstation, not a dedicated bench rig. Versions: @svgrid/grid 3.0.3, wx-svelte-grid 2.7.0. Lower is better.\n\n| Operation | SvGrid | SVAR Svelte DataGrid |\n| --- | --- | --- |\n| Mount | 75.5 ms | 11.4 ms |\n| Sort, text column | 149 ms | 187.2 ms |\n| Sort, numeric column | 115.7 ms | 165.1 ms |\n| Filter, one column (indicative only) | 99.6 ms | 32.6 ms |\n| Scroll, p95 frame | 34.6 ms | 34.8 ms |\n| Rows kept in the DOM (virtualization on) | 27 | 19 |\n\nThe filter row is not like for like: each grid is driven through its own single-column filter API, and the amount of work differs. The comparison guide explains the method, what is left out and why.\n\n## When to choose SvGrid\n\n- You need grouping with aggregation, master/detail, Excel-style range editing or pivot tables, which SVAR's docs do not list.\n- You want a headless engine plus a render component, not a component-only API.\n- You want integrated charts and a full server-side row model in one library.\n- You want in-grid AI helpers, an MCP server that checks generated code, and a paid support tier.\n\n## When to choose SVAR Svelte DataGrid\n\n- You want a fully free grid with print included and no paid tier at all.\n- You ship to React and Vue as well as Svelte and want one grid across them.\n- A smaller bundle matters more than the features above.\n- You are already adopting the wider SVAR suite: Gantt, Calendar, Kanban, File Manager.\n\n## Migration effort\n\nEstimated effort: 2-4 hours per grid.\n\nWhat you give up:\n\n- Free printing: SVAR's print API is in the MIT grid, SvGrid's print view is in @svgrid/enterprise.\n- The React and Vue versions of the same grid.\n- A smaller bundle, by the measurements in the At a glance table.\n- The SVAR suite around the grid: Gantt, Calendar, Kanban and File Manager share its core.\n\nMigration guide: moving from SVAR Svelte DataGrid to SvGrid: https://svgrid.com/docs/help/migrating-from-svar-svelte-datagrid/\n\n## Live example\n\nGrouping Aggregation: open it in the gallery for the source and the full-size version. https://svgrid.com/demos/07-grouping-aggregation/\n\n## The bottom line\n\nBoth grids are Svelte-5-native and MIT, so this is not a licensing call. On capability SvGrid is the more complete grid: grouping, master/detail, range editing with a fill handle, charts, a server-side row model, a headless core, AI helpers and an MCP server. SVAR is the smaller, fully free, multi-framework option from the Webix team, and it prints for free where SvGrid charges for print and Excel and PDF export. Choose SvGrid when you need the deeper feature set or support; choose SVAR when a compact free grid covers your needs or you also ship React and Vue.\n\n## Frequently asked questions\n\n### SvGrid vs SVAR Svelte DataGrid: what is the difference?\n\nBoth are MIT-licensed, Svelte-5-native grids. SvGrid is the broader product: row grouping with aggregation, master/detail, Excel-style range selection with a fill handle, integrated charts, a server-side row model, a headless core, in-grid AI helpers and an MCP server. SVAR is a smaller, fully free grid with React and Vue versions from XB Software, with CSV export and a print API included.\n\n### Are SvGrid and SVAR both free?\n\nBoth are free under MIT, including commercial use. SVAR keeps the whole grid free, CSV export and print included, and sells PRO editions of its Gantt, Calendar and Kanban. SvGrid's grid is free too, including CSV, TSV and JSON export, charts and the AI helpers; Excel, PDF and print output, import, pivot tables, the Kanban and Scheduler views and support are in @svgrid/enterprise at $599 per developer per year.\n\n### Are both built for Svelte 5?\n\nYes. SvGrid is written in Svelte 5 runes, and svar.dev states the DataGrid is Svelte 5 compatible. Neither is a cross-framework wrapper, although SVAR also ships React and Vue versions of its grid.\n\n### Which grid is smaller?\n\nSVAR, by the measurements in the At a glance table: both packages were built alone with Vite, minified and gzipped with Svelte external, on the dates shown. SvGrid's extra size buys grouping, master/detail, range editing, charts and the server-side row model; features you never import, such as the date editors, menus and charts, load as separate chunks.\n\n### Does SVAR have row grouping, master/detail or cell-range selection?\n\nNot according to its docs overview on the date we read it, which lists tree data, single and multiple row selection, header and advanced filters, sorting, in-cell editing, columns pinned to the left, CSV export and a print API. SvGrid has all three in the MIT core, and the demos on this page show them.\n\n### How long does a SVAR to SvGrid migration take?\n\nThe migration guide budgets two to four hours per grid: a prop and event rename pass, since both use array-of-object column definitions, plus re-theming through --sg-* tokens.\n\n### Is SvGrid a good SVAR Svelte DataGrid alternative for Svelte?\n\nThe closest comparison on this list, since both are Svelte-native and both are MIT, so licensing does not decide it. The differences are depth and direction: SvGrid ships a larger feature surface, a UI component suite, in-grid AI helpers and an MCP server, while SVAR spans Svelte, React and Vue and keeps a smaller core. The At a glance table above has both measured bundle sizes; if a compact MIT grid with sorting, filtering, editing, tree data and CSV export is all you need, SVAR is a perfectly good answer.\n\n## Related comparisons and docs\n\n- [SvGrid vs svelte-headless-table](https://svgrid.com/compare/svelte-headless-table/)\n- [SvGrid vs TanStack Table (Svelte)](https://svgrid.com/compare/tanstack-table/)\n- [SvGrid vs @vincjo/datatables](https://svgrid.com/compare/vincjo-datatables/)\n- [Comparison: SvGrid vs AG Grid vs TanStack Table](https://svgrid.com/docs/help/comparison/)\n- [Grouping & aggregation](https://svgrid.com/docs/help/grouping-aggregation/)\n- [Master / detail (nested grids)](https://svgrid.com/docs/help/rows/master-detail/)\n- [Build a table from scratch](https://svgrid.com/docs/help/headless/build-a-table/)\n\n## Sources and last verified\n\nEvery claim on this page was last checked on 12 Sep 2026. Versions, licences and download counts come from the npm registry; feature and pricing statements from the pages listed below.\n\n- svar-datagrid: Licensed under MIT; Svelte 5 compatible; React and Vue versions available; lists multi-column sorting, header filters, in-cell editing, tree data, virtual scrolling, columns pinned to the left, context menu, row drag-and-drop, checkbox selection, pagination, hotkeys, WAI-ARIA, print, undo/redo (checked 12 Sep 2026) https://svar.dev/svelte/datagrid/\n- svar-overview: Feature list: in-cell editing, header and advanced filtering, sorting, single and multiple row selection, row reordering, context menu, undo/redo, tree data, pagination, colspans and rowspans in header and footer, collapsible column groups, pinned columns to the left, auto-sizing of rows and columns, localization, themes, export to CSV, print API, RestDataProvider, virtual scrolling for rows and columns, WAI-ARIA, keyboard navigation; no Excel export, row grouping, aggregation, master/detail, charts, AI or MCP (checked 12 Sep 2026) https://docs.svar.dev/svelte/grid/overview/\n- svar-svelte: DataGrid, Filter, Editor, File Manager and Core are MIT; Gantt, Calendar and Kanban have MIT cores with paid PRO editions; no pivot component in the list; no price list on the page (checked 12 Sep 2026) https://svar.dev/svelte/\n- svar-gantt: Offers paid consulting and custom development services; PRO edition pricing is on a separate page (checked 12 Sep 2026) https://svar.dev/svelte/gantt/\n"
|
|
6992
|
+
"markdown": "# SvGrid vs SVAR Svelte DataGrid\n\nCanonical URL: https://svgrid.com/compare/svar-svelte-datagrid/\nFacts verified: 2026-09-12\nCompetitor package: wx-svelte-grid\nCompetitor site: https://svar.dev/svelte/datagrid/\n\nSVAR Svelte DataGrid (wx-svelte-grid) is a Svelte-native, MIT-licensed data grid from XB Software, the team behind Webix, with React and Vue versions of the same grid.\n\n## Verdict\n\nSVAR is the closest genuinely Svelte-native rival: both grids are MIT and both target Svelte 5. SvGrid has the wider capability surface (grouping with aggregation, master/detail, Excel-style range editing with a fill handle, integrated charts, a headless core, in-grid AI helpers and an MCP server); SVAR is the smaller grid with print in the free package, React and Vue versions, and the Webix team behind it.\n\nMigration guide: moving from SVAR Svelte DataGrid to SvGrid: https://svgrid.com/docs/help/migrating-from-svar-svelte-datagrid/\n\n## At a glance\n\n| Fact | SvGrid | SVAR Svelte DataGrid | Checked |\n| --- | --- | --- | --- |\n| Latest version | 3.0.3 | 2.7.0 | 12 Sep 2026 |\n| Licence field on npm | MIT | MIT | 12 Sep 2026 |\n| Last published | 11 Sep 2026 | 3 Jun 2026 | 12 Sep 2026 |\n| Svelte 5 support | Native (Svelte 5 runes) | Svelte package, no peer range declared | 12 Sep 2026 |\n| npm downloads, 30 days to 10 Sep 2026 | 16,900 | 62,800 | 12 Sep 2026 |\n| Bundle, minified + gzip | 97.6 KB JS + 10.5 KB CSS | 51.5 KB JS, no separate stylesheet, svelte external | 12 Sep 2026 |\n| Engine alone, minified + gzip | 2.7 KB JS, no separate stylesheet (`createSvGrid` from `@svgrid/grid/core`) | the row above; the package is the engine | 22 Sep 2026 |\n| Frameworks | Svelte 5 | Svelte, React, Vue | 12 Sep 2026 |\n| Pricing | MIT core; @svgrid/enterprise from $299 per developer per year (Indie, under $1M revenue), $599 for Enterprise | The DataGrid is MIT and free for commercial use with no paid tier; svar.dev sells PRO editions of its Gantt, Calendar and Kanban components and offers paid consulting and custom development, with no price list for the grid | 12 Sep 2026 |\n\nBundle sizes: each package built alone with Vite in library mode, minified, gzip level 9, Svelte kept external where a package uses it (it is a peer dependency). SvGrid 3.0.4 measured 22 Sep 2026 with packages/grid/scripts/measure-size.mjs; wx-svelte-grid 2.7.0 entry `Grid component` measured 12 Sep 2026 with packages/grid/scripts/measure-competitor-bundles.mjs.\n\n## Overview\n\nSVAR DataGrid (npm: wx-svelte-grid) is part of the SVAR suite from XB Software, the makers of Webix, and is one of the few grids built for Svelte rather than wrapped from another framework. Its docs list in-cell editing, header and advanced filtering, single and multi-column sorting, tree data, virtual scrolling for rows and columns, columns pinned to the left, column and row spans in the header and footer, auto-sized rows, undo and redo, a context menu, row reordering, CSV export, a print API and a REST data provider, all under MIT.\n\nSvGrid overlaps on the Svelte-native angle and reaches further: row grouping with aggregation, master/detail, Excel-style cell-range selection with clipboard and a fill handle, pinned rows and left and right column pinning, integrated charts, a server-side row model, a headless engine, in-grid AI helpers and the @svgrid/mcp server, all in the MIT package. Excel, PDF and print output, import, pivot tables and the Kanban and Scheduler views of the grid live in the paid @svgrid/enterprise pack, whereas SVAR keeps its grid entirely free and sells PRO editions of its Gantt, Calendar and Kanban instead.\n\n## Looking for a SVAR Svelte DataGrid alternative for Svelte?\n\nThe closest comparison on this list, since both are Svelte-native and both are MIT, so licensing does not decide it. The differences are depth and direction: SvGrid ships a larger feature surface, a UI component suite, in-grid AI helpers and an MCP server, while SVAR spans Svelte, React and Vue and keeps a smaller core. The At a glance table above has both measured bundle sizes; if a compact MIT grid with sorting, filtering, editing, tree data and CSV export is all you need, SVAR is a perfectly good answer.\n\n## What they have in common\n\n- Purpose-built for Svelte 5, not a cross-framework wrapper.\n- MIT-licensed and free for commercial use.\n- Sorting, filtering, in-cell editing, virtualization on rows and columns, tree data.\n- Auto-sized row heights, undo and redo, a context menu and drag-and-drop row reordering.\n- Themeable through CSS variables with light and dark themes, localization, WAI-ARIA markup and keyboard navigation.\n\n## Where SvGrid is stronger\n\n- Row grouping with aggregation and a drag-and-drop group panel; SVAR's docs list neither.\n- Master/detail and expandable detail rows; SVAR offers tree data only.\n- Excel-style cell-range selection with clipboard copy and paste and a fill handle; SVAR selects rows.\n- Pinned top and bottom rows, and columns pinned left and right; SVAR pins columns to the left only.\n- Integrated charts with no dependency, plus a chart wizard.\n- A server-side row model with cursor pagination, GraphQL, websocket and optimistic updates, beyond a REST data provider.\n- A headless engine (createSvGrid) you can compose, in addition to the render component.\n- In-grid AI helpers free in @svgrid/grid, and @svgrid/mcp with llms.txt so assistants answer and write code accurately.\n- A paid pack with Excel, PDF and styled-HTML export, print, pivot tables, Excel and CSV import and support. CSV, TSV and JSON export are free in the grid.\n\n## Where SVAR Svelte DataGrid is stronger\n\n- The whole grid is free, print API included; SvGrid puts print and Excel and PDF export in the paid pack. Both export CSV for free.\n- The same grid for React and Vue as well as Svelte; SvGrid is Svelte-only by design.\n- A smaller bundle: the At a glance table has both measured numbers.\n- XB Software and Webix behind it, a team that has built data grids for a long time.\n- Part of the wider SVAR suite, with paid consulting and custom development on offer.\n\n## Feature by feature\n\nYes: shipped in the package. Partial: needs extra work or a companion package. Paid tier: only in a paid edition. No: not available. n/a: does not apply.\n\n| Feature | SvGrid | SVAR Svelte DataGrid |\n| --- | --- | --- |\n| Svelte 5 native | Yes | Yes - Svelte 5 compatible |\n| Licence | Yes - MIT core, paid enterprise pack | Yes - MIT, the grid is entirely free |\n| Headless engine | Yes - createSvGrid | No - component only |\n| Excel-style filter menu | Yes - built in | Yes - header filters plus the SVAR Filter component |\n| Cell-range selection and clipboard | Yes - built in | No - single and multiple row selection |\n| Fill handle | Yes | No - not in the feature list |\n| Row grouping with aggregation | Yes - with a group panel | No - not in the feature list |\n| Master/detail rows | Yes | No - tree data only |\n| Tree data | Yes | Yes |\n| Pinned columns | Yes - left and right | Partial - to the left |\n| Pinned rows (top and bottom) | Yes | No - not in the feature list |\n| Header and footer column spans | Yes | Yes |\n| Auto-sized row height | Yes - autoRowHeight | Yes |\n| Virtualization (rows and columns) | Yes | Yes |\n| Undo and redo, context menu, row drag | Yes | Yes |\n| Integrated charts | Yes - no dependency, plus a chart wizard | No - not in the feature list |\n| Server-side data, flat (sort, filter, paging, infinite scroll) | Yes - createServerDataSource: page or infinite block scroll, cursor, GraphQL, websocket | Partial - RestDataProvider and dynamic loading while scrolling |\n| Server-side row model (lazy grouping, tree, pivot, transactions, select-all across unloaded rows) | Paid tier - @svgrid/enterprise | No - not in the feature list |\n| CSV export | Yes - free, with TSV and JSON | Yes - free |\n| Excel and PDF export | Paid tier - @svgrid/enterprise | No - CSV only in the feature list |\n| Print | Paid tier - @svgrid/enterprise | Yes - print API, free |\n| Pivot tables | Paid tier - @svgrid/enterprise | No - not in the SVAR Svelte product list |\n| React and Vue versions | No - Svelte only | Yes |\n| In-grid AI helpers and MCP server | Yes - helpers free in @svgrid/grid; @svgrid/mcp, MIT | No - not mentioned in the docs |\n| Paid support | Yes - with @svgrid/enterprise, per developer per year | Partial - paid consulting and custom development; no support plan for the grid listed |\n\n## Measured performance\n\nMeasured 12 Sep 2026 with the harness in the repository (pnpm bench:compare): 100,000 rows, fastest of 7 samples per operation, each grid in a fresh page, Chromium through Playwright, headless, on win32 10.0.26200 x64, Intel(R) Core(TM) Ultra 7 255U; a developer workstation, not a dedicated bench rig. Versions: @svgrid/grid 3.0.3, wx-svelte-grid 2.7.0. Lower is better.\n\n| Operation | SvGrid | SVAR Svelte DataGrid |\n| --- | --- | --- |\n| Mount | 75.5 ms | 11.4 ms |\n| Sort, text column | 149 ms | 187.2 ms |\n| Sort, numeric column | 115.7 ms | 165.1 ms |\n| Filter, one column (indicative only) | 99.6 ms | 32.6 ms |\n| Scroll, p95 frame | 34.6 ms | 34.8 ms |\n| Rows kept in the DOM (virtualization on) | 27 | 19 |\n\nThe filter row is not like for like: each grid is driven through its own single-column filter API, and the amount of work differs. The comparison guide explains the method, what is left out and why.\n\n## When to choose SvGrid\n\n- You need grouping with aggregation, master/detail, Excel-style range editing or pivot tables, which SVAR's docs do not list.\n- You want a headless engine plus a render component, not a component-only API.\n- You want integrated charts and a full server-side row model in one library.\n- You want in-grid AI helpers, an MCP server that checks generated code, and a paid support tier.\n\n## When to choose SVAR Svelte DataGrid\n\n- You want a fully free grid with print included and no paid tier at all.\n- You ship to React and Vue as well as Svelte and want one grid across them.\n- A smaller bundle matters more than grouping with aggregation, master/detail, range editing and the other features SvGrid adds.\n- You are already adopting the wider SVAR suite: Gantt, Calendar, Kanban, File Manager.\n\n## Migration effort\n\nEstimated effort: 2-4 hours per grid.\n\nWhat you give up:\n\n- Free printing: SVAR's print API is in the MIT grid, SvGrid's print view is in @svgrid/enterprise.\n- The React and Vue versions of the same grid.\n- A smaller bundle, by the measurements in the At a glance table.\n- The SVAR suite around the grid: Gantt, Calendar, Kanban and File Manager share its core.\n\nMigration guide: moving from SVAR Svelte DataGrid to SvGrid: https://svgrid.com/docs/help/migrating-from-svar-svelte-datagrid/\n\n## Live example\n\nGrouping Aggregation: open it in the gallery for the source and the full-size version. https://svgrid.com/demos/07-grouping-aggregation/\n\n## The bottom line\n\nBoth grids are Svelte-5-native and MIT, so this is not a licensing call. On capability SvGrid is the more complete grid: grouping, master/detail, range editing with a fill handle, charts, a server-side row model, a headless core, AI helpers and an MCP server. SVAR is the smaller, fully free, multi-framework option from the Webix team, and it prints for free where SvGrid charges for print and Excel and PDF export. Choose SvGrid when you need the deeper feature set or support; choose SVAR when a compact free grid covers your needs or you also ship React and Vue.\n\n## Frequently asked questions\n\n### SvGrid vs SVAR Svelte DataGrid: what is the difference?\n\nBoth are MIT-licensed, Svelte-5-native grids. SvGrid is the broader product: row grouping with aggregation, master/detail, Excel-style range selection with a fill handle, integrated charts, a server-side row model, a headless core, in-grid AI helpers and an MCP server. SVAR is a smaller, fully free grid with React and Vue versions from XB Software, with CSV export and a print API included.\n\n### Are SvGrid and SVAR both free?\n\nBoth are free under MIT, including commercial use. SVAR keeps the whole grid free, CSV export and print included, and sells PRO editions of its Gantt, Calendar and Kanban. SvGrid's grid is free too, including CSV, TSV and JSON export, charts and the AI helpers; Excel, PDF and print output, import, pivot tables, the Kanban and Scheduler views and support are in @svgrid/enterprise at $599 per developer per year.\n\n### Are both built for Svelte 5?\n\nYes. SvGrid is written in Svelte 5 runes, and svar.dev states the DataGrid is Svelte 5 compatible. Neither is a cross-framework wrapper, although SVAR also ships React and Vue versions of its grid.\n\n### Which grid is smaller?\n\nSVAR, by the measurements in the At a glance table: both packages were built alone with Vite, minified and gzipped with Svelte external, on the dates shown. SvGrid's extra size buys grouping, master/detail, range editing, charts and the server-side row model; features you never import, such as the date editors, menus and charts, load as separate chunks.\n\n### Does SVAR have row grouping, master/detail or cell-range selection?\n\nNot according to its docs overview on the date we read it, which lists tree data, single and multiple row selection, header and advanced filters, sorting, in-cell editing, columns pinned to the left, CSV export and a print API. SvGrid has all three in the MIT core, and the demos on this page show them.\n\n### How long does a SVAR to SvGrid migration take?\n\nThe migration guide budgets two to four hours per grid: a prop and event rename pass, since both use array-of-object column definitions, plus re-theming through --sg-* tokens.\n\n### Is SvGrid a good SVAR Svelte DataGrid alternative for Svelte?\n\nThe closest comparison on this list, since both are Svelte-native and both are MIT, so licensing does not decide it. The differences are depth and direction: SvGrid ships a larger feature surface, a UI component suite, in-grid AI helpers and an MCP server, while SVAR spans Svelte, React and Vue and keeps a smaller core. The At a glance table above has both measured bundle sizes; if a compact MIT grid with sorting, filtering, editing, tree data and CSV export is all you need, SVAR is a perfectly good answer.\n\n## Related comparisons and docs\n\n- [SvGrid vs svelte-headless-table](https://svgrid.com/compare/svelte-headless-table/)\n- [SvGrid vs TanStack Table (Svelte)](https://svgrid.com/compare/tanstack-table/)\n- [SvGrid vs @vincjo/datatables](https://svgrid.com/compare/vincjo-datatables/)\n- [Comparison: SvGrid vs AG Grid vs TanStack Table](https://svgrid.com/docs/help/comparison/)\n- [Grouping & aggregation](https://svgrid.com/docs/help/grouping-aggregation/)\n- [Master / detail (nested grids)](https://svgrid.com/docs/help/rows/master-detail/)\n- [Build a table from scratch](https://svgrid.com/docs/help/headless/build-a-table/)\n\n## Sources and last verified\n\nEvery claim on this page was last checked on 12 Sep 2026. Versions, licences and download counts come from the npm registry; feature and pricing statements from the pages listed below.\n\n- svar-datagrid: Licensed under MIT; Svelte 5 compatible; React and Vue versions available; lists multi-column sorting, header filters, in-cell editing, tree data, virtual scrolling, columns pinned to the left, context menu, row drag-and-drop, checkbox selection, pagination, hotkeys, WAI-ARIA, print, undo/redo (checked 12 Sep 2026) https://svar.dev/svelte/datagrid/\n- svar-overview: Feature list: in-cell editing, header and advanced filtering, sorting, single and multiple row selection, row reordering, context menu, undo/redo, tree data, pagination, colspans and rowspans in header and footer, collapsible column groups, pinned columns to the left, auto-sizing of rows and columns, localization, themes, export to CSV, print API, RestDataProvider, virtual scrolling for rows and columns, WAI-ARIA, keyboard navigation; no Excel export, row grouping, aggregation, master/detail, charts, AI or MCP (checked 12 Sep 2026) https://docs.svar.dev/svelte/grid/overview/\n- svar-svelte: DataGrid, Filter, Editor, File Manager and Core are MIT; Gantt, Calendar and Kanban have MIT cores with paid PRO editions; no pivot component in the list; no price list on the page (checked 12 Sep 2026) https://svar.dev/svelte/\n- svar-gantt: Offers paid consulting and custom development services; PRO edition pricing is on a separate page (checked 12 Sep 2026) https://svar.dev/svelte/gantt/\n"
|
|
6993
6993
|
},
|
|
6994
6994
|
{
|
|
6995
6995
|
"slug": "compare/svelte-headless-table",
|
|
@@ -7108,8 +7108,8 @@ export const apiReference = {
|
|
|
7108
7108
|
]
|
|
7109
7109
|
};
|
|
7110
7110
|
export const apiSurface = {
|
|
7111
|
-
"gridVersion": "3.0.
|
|
7112
|
-
"enterpriseVersion": "3.1.
|
|
7111
|
+
"gridVersion": "3.0.10",
|
|
7112
|
+
"enterpriseVersion": "3.1.6",
|
|
7113
7113
|
"grid": {
|
|
7114
7114
|
"values": [
|
|
7115
7115
|
"ALL_FILTER_OPERATORS",
|
package/dist/preview.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export declare const UI_RESOURCE_URI = "ui://svgrid/preview.html";
|
|
|
8
8
|
* start failing in a way nobody is watching for. `tools/mcp-tools.test.ts` checks these
|
|
9
9
|
* against the workspace so they cannot quietly rot either.
|
|
10
10
|
*/
|
|
11
|
-
export declare const PREVIEW_GRID_WC_VERSION = "3.0.
|
|
11
|
+
export declare const PREVIEW_GRID_WC_VERSION = "3.0.11";
|
|
12
12
|
export declare function previewResource(): {
|
|
13
13
|
uri: string;
|
|
14
14
|
name: string;
|
package/dist/preview.js
CHANGED
|
@@ -27,7 +27,7 @@ const UI_RESOURCE_META_KEY = 'ui/resourceUri';
|
|
|
27
27
|
* start failing in a way nobody is watching for. `tools/mcp-tools.test.ts` checks these
|
|
28
28
|
* against the workspace so they cannot quietly rot either.
|
|
29
29
|
*/
|
|
30
|
-
export const PREVIEW_GRID_WC_VERSION = '3.0.
|
|
30
|
+
export const PREVIEW_GRID_WC_VERSION = '3.0.11';
|
|
31
31
|
const EXT_APPS_VERSION = '1.7.5';
|
|
32
32
|
const CDN = 'https://cdn.jsdelivr.net/npm';
|
|
33
33
|
/**
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"type": "commercial",
|
|
6
6
|
"url": "https://svgrid.com/pricing"
|
|
7
7
|
},
|
|
8
|
-
"version": "3.0.
|
|
8
|
+
"version": "3.0.11",
|
|
9
9
|
"description": "Model Context Protocol server for SvGrid, the Svelte 5 data grid: checks the code your AI writes against the real API surface, plus version-pinned docs, API reference and 373 demo sources.",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"author": "jQWidgets <sales@jqwidgets.com>",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
34
34
|
"svelte": "^5.55.5",
|
|
35
35
|
"zod": "^3.23.8",
|
|
36
|
-
"@svgrid/enterprise": "^3.1.
|
|
36
|
+
"@svgrid/enterprise": "^3.1.6"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^22.10.7",
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "com.svgrid/svgrid",
|
|
4
4
|
"title": "SvGrid",
|
|
5
5
|
"description": "Checks AI-written SvGrid code against the real API, plus version-pinned Svelte 5 grid docs.",
|
|
6
|
-
"version": "3.0.
|
|
6
|
+
"version": "3.0.11",
|
|
7
7
|
"websiteUrl": "https://svgrid.com/docs/help/mcp-server/",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/sv-grid/sv-grid",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"registryType": "npm",
|
|
16
16
|
"registryBaseUrl": "https://registry.npmjs.org",
|
|
17
17
|
"identifier": "@svgrid/mcp",
|
|
18
|
-
"version": "3.0.
|
|
18
|
+
"version": "3.0.11",
|
|
19
19
|
"runtimeHint": "npx",
|
|
20
20
|
"transport": {
|
|
21
21
|
"type": "stdio"
|