Named views
Save the grid sort + filter + layout as a named view and restore it in one click. createNamedViews(api, { storage }) wraps getState/setState; localStorageViews persists across reloads, or plug your own server adapter.
A live, editable Svelte 5 data grid example from the SvGrid gallery (Rows & Cells). See the SvGrid documentation for the full API.
About this example
Named views for the Svelte 5 data grid: save the current sort, filters and column layout under a name and restore it in one click. createNamedViews(api, { storage }) wraps the grid's getState() and setState() with a save, load, list and delete manager; localStorageViews(key) persists views across reloads, and a custom storage adapter syncs per-user views to a server.
Save the grid's current sort + filter + column layout as a named view and restore it in one click. createNamedViews(api, { storage }) wraps the grid's getState() / setState() with a save / load / list / delete manager. localStorageViews(key) persists across reloads; swap in your own adapter to sync per-user views to a server.
Imports, features and API used
Imports: @svgrid/grid, ../shared/seed
Table features registered: rowSortingFeature, columnFilteringFeature
Columns: firstName (First name), lastName (Last name), department (Department), country (Country), age (Age), salary (Salary)
Frequently asked questions
How do I save the current grid layout?
Create the manager once the API is ready with createNamedViews(api, { storage: localStorageViews('my-grid') }), then call its save method with a name. It reads api.getState() and stores it under that key.
How do I sync views to a server?
Pass your own storage adapter with the same load, save and delete shape as localStorageViews, backed by fetch calls to your API, and views become per user.
What is captured in a view?
Whatever api.getState() returns: sorting, filters, column order, visibility and widths. Restoring calls api.setState with the stored object.
Related documentation
Related articles
- Saved Views - Persist Grid Layout and Filters - Give users named, switchable snapshots of column order, sorting, filters, and grouping - persisted to localStorage or a server adapter - using SvGrid's createNamedViews API.
Source code (143-named-views.svelte)
<!-- Documented in: docs/help/state/named-views.md -->
<script lang="ts">
/**
* 143. Named views
* ----------------
* Save the grid's current sort + filter + column layout as a named view
* and restore it in one click. `createNamedViews(api, { storage })` wraps
* the grid's `getState()` / `setState()` with a save / load / list / delete
* manager. `localStorageViews(key)` persists across reloads; swap in your
* own adapter to sync per-user views to a server.
*/
import {
SvGrid,
tableFeatures,
rowSortingFeature,
columnFilteringFeature,
createNamedViews,
localStorageViews,
type GridColumns,
type SvGridApi,
type SavedView,
} from '@svgrid/grid'
import { makePeople, type Person } from '../shared/seed'
const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
const rows = makePeople(300)
const columns: GridColumns<Person> = [
{ field: 'firstName', header: 'First name', width: 140 },
{ field: 'lastName', header: 'Last name', width: 140 },
{ field: 'department', header: 'Department', width: 150 },
{ field: 'country', header: 'Country', width: 120 },
{ field: 'age', header: 'Age', width: 90, align: 'right' },
{
field: 'salary',
header: 'Salary',
width: 140,
format: { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } },
},
]
let api = $state<SvGridApi<typeof features, Person> | null>(null)
let manager = $state<ReturnType<typeof createNamedViews> | null>(null)
let views = $state<SavedView[]>([])
let name = $state('')
function refresh() {
views = manager?.list() ?? []
}
function onReady(a: SvGridApi<typeof features, Person>) {
api = a
manager = createNamedViews(a, { storage: localStorageViews('sv-grid-demo-views') })
refresh()
}
function save() {
const n = name.trim()
if (!n || !manager) return
manager.save(n)
name = ''
refresh()
}
function load(v: string) {
manager?.load(v)
}
function remove(v: string) {
manager?.remove(v)
refresh()
}
</script>
<section class="flex flex-col flex-1 min-h-0 gap-3">
<div
class="shrink-0 rounded-lg border px-4 py-3"
style="border-color: var(--sg-border); background: var(--sg-header-bg);"
>
<p class="text-sm font-semibold" style="color: var(--sg-fg);">
Save & restore layouts via <code>createNamedViews</code>
</p>
<p class="mt-1 text-xs" style="color: var(--sg-muted);">
Sort / filter the grid, type a name, and Save. Reload the page - your
views persist (localStorage). Click a view to restore it.
</p>
<div class="mt-3 flex flex-wrap items-center gap-2">
<input
class="nv-input"
placeholder="View name (e.g. 'Top earners')"
bind:value={name}
onkeydown={(e) => e.key === 'Enter' && save()}
/>
<button type="button" class="nv-btn nv-primary" onclick={save}>Save current</button>
{#each views as v (v.name)}
<span class="nv-chip">
<button type="button" class="nv-chip-load" onclick={() => load(v.name)}>{v.name}</button>
<button type="button" class="nv-chip-x" aria-label={`Delete ${v.name}`} onclick={() => remove(v.name)}>×</button>
</span>
{/each}
{#if views.length === 0}
<span class="text-xs" style="color: var(--sg-muted);">No saved views yet.</span>
{/if}
</div>
</div>
<div class="flex-1 min-h-0">
<SvGrid responsive={true}
columnResize
data={rows}
columns={columns}
features={features}
sortable
filterable
selectionMode="none"
rowHeight={34}
containerHeight="100%"
fitColumns={true}
onApiReady={onReady}
/>
</div>
</section>
<style>
.nv-input {
border: 1px solid var(--sg-input-border, var(--sg-border));
background: var(--sg-input-bg, var(--sg-bg));
color: var(--sg-fg);
border-radius: 6px;
padding: 5px 10px;
font-size: 12.5px;
min-width: 220px;
}
.nv-btn {
padding: 5px 12px;
border-radius: 6px;
border: 1px solid var(--sg-border);
background: var(--sg-bg);
color: var(--sg-fg);
font-size: 12.5px;
cursor: pointer;
}
.nv-primary {
background: var(--sg-accent);
border-color: var(--sg-accent);
color: var(--sg-on-accent, #fff);
font-weight: 600;
}
.nv-chip {
display: inline-flex;
align-items: stretch;
border: 1px solid var(--sg-border);
border-radius: 999px;
overflow: hidden;
font-size: 12px;
}
.nv-chip-load {
border: 0;
background: transparent;
color: var(--sg-fg);
padding: 4px 6px 4px 12px;
cursor: pointer;
}
.nv-chip-load:hover { color: var(--sg-accent); }
.nv-chip-x {
border: 0;
background: transparent;
color: var(--sg-muted);
padding: 0 9px;
font-size: 15px;
cursor: pointer;
}
.nv-chip-x:hover { color: #ef4444; }
</style>More Rows & Cells examples
- Managed row dragging (grid-to-grid) - Reorder rows by dragging their grip, or move a row from one grid into another - both grids share a rowDragGroup, so the row leaves the source and lands in the target. The grid mutates its own data on drop and fires onRowDragEnd on the receiver.
- External drop zones (row drag) - Drag a row out of the grid onto any element - an Archive or Delete bucket - via the rowDropZone action. The row leaves the grid and the zone's onDrop handles it. In-grid reorder still works.
- Custom cells + themes - Avatars, sparklines, progress bars, density toggle, dark mode, full a11y.
- Sparkline cells - In-cell mini charts as a first-class column type: set `sparkline` on a number-array column and the grid paints an inline SVG. Line, area, bar (with +/- coloring), and win/loss - no chart library, no custom snippet.
- Conditional formatting (engine) - Excel-style value-driven cell coloring as a declarative `conditionalFormats` engine prop: gradient heat maps (alpha ramp, zero-centred, banded, column-comparison), in-cell data bars, icon sets, and predicate rules - scoped per column, no per-cell snippet.