View refresh
The grid renders reactively - it does not have a refresh() method,
because it doesn't need one. To make the grid re-display, change the data
that drives it.
Forcing a refresh
| You want | Do this |
|---|---|
| Re-display every row | Reassign data to a new array (rows = [...rows]). |
| Re-display one row | Mutate the row through a $state array, or call api.setCellValue(...). |
| Re-apply sort / filter / page | Update the controlled state slice (or reassign the data). |
| Re-render a single cell | The grid's renderer keys on the cell's cellId. Changing the underlying value re-renders the cell. |
When the grid does NOT re-render
If you mutate a row object deeply without going through $state -
e.g. someExternalRef.salary = 50000 where someExternalRef is an object
held outside the grid - Svelte 5 will not know to update.
Two safe patterns:
The examples on this page run against these rows:
<script lang="ts">
import { SvGrid, type GridColumns } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
{ id: 5, name: 'Barbara Liskov', department: 'Platform', city: 'Boston', age: 52, salary: 172000 },
]
let rows = $state<Person[]>(people)
const data = people
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 200 },
{ field: 'department', header: 'Department', width: 150 },
{ field: 'city', header: 'City', width: 140 },
{ field: 'age', header: 'Age', width: 90 },
{ field: 'salary', header: 'Salary', width: 130, format: { type: 'currency', currency: 'USD' } },
]
</script>
<script lang="ts">
let rows = $state<Person[]>(initial)
// ✅ via $state proxy
rows[0]!.salary = 50_000
// ✅ via array reassignment
rows = rows.map((r, i) => (i === 0 ? { ...r, salary: 50_000 } : r))
// ✅ via API
api?.setCellValue(0, 'salary', 50_000)
</script>
Refresh-after-async
For data fetched asynchronously, the array reassignment is the canonical trigger:
<script lang="ts">
let rows = $state<Person[]>([])
$effect(() => { fetchRows().then((next) => (rows = next)) })
</script>
Try it
The button below reassigns rows to a brand new array. That is the whole
refresh mechanism - there is no refresh() to call.
<button type="button" onclick={() => (rows = rows.map((r) => ({ ...r, salary: r.salary + 1000 })))}>
Give everyone a raise
</button>
<SvGrid data={rows} {columns} />
Refreshing one row
You do not need to refresh the whole grid to change one row. Replacing that row's slot with a new object is enough, and it is cheaper than rebuilding the array, because only the one row re-renders.
<script lang="ts">
import { SvGrid, renderSnippet, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const seed: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
]
let rows = $state<Person[]>(seed.map((p) => ({ ...p })))
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 190 },
{ field: 'salary', header: 'Salary', width: 150,
format: { type: 'currency', currency: 'USD' } },
]
function raise(i: number) {
rows[i] = { ...rows[i]!, salary: rows[i]!.salary + 5000 }
}
</script>
<button type="button" onclick={() => raise(0)}>Raise the first row</button>
<SvGrid data={rows} {columns} />
When the value did not change but the rendering should
A cell renderer that reads something outside the row - a clock, a threshold, a currently-selected id - will not re-render when that thing moves, because the row is untouched. Make the outside thing part of what the renderer is given and the problem disappears; reaching for a manual refresh here is treating the symptom.
<script lang="ts">
import { SvGrid, renderSnippet, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const seed: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
]
let threshold = $state(150000)
const columns: GridColumns<Person> = $derived([
{ field: 'name', header: 'Name', width: 180 },
{ field: 'salary', header: 'Salary', width: 200,
// threshold is read here, so the column list is derived and the cells
// re-render when the slider moves. No refresh call needed.
cell: (ctx) => renderSnippet(Money, {
value: Number(ctx.getValue() ?? 0),
over: Number(ctx.getValue() ?? 0) > threshold,
}) },
])
</script>
{#snippet Money(props: { value: number; over: boolean })}
<span style={props.over ? 'font-weight: 600;' : 'opacity: 0.7;'}>
{props.value.toLocaleString('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 })}
</span>
{/snippet}
<label>
Highlight above {threshold.toLocaleString()}
<input type="range" min="130000" max="180000" step="1000" bind:value={threshold} />
</label>
<SvGrid data={seed} {columns} />