Accessing rows

You can read the grid's current rows in three ways.

Open the live example: Selection + copy/paste (Selection & Clipboard)

1. From the imperative API

api.getData() returns the underlying data array - pre-sort, pre-filter, pre-paginate. Use this when you want to know what the grid is showing before its row model has been applied.

<script lang="ts">
  let api: SvGridApi<{}, Person> | null = $state(null)
</script>

<SvGrid {data} {columns} features={{}} onApiReady={(next) => (api = next)} />

<button onclick={() => console.log(api?.getData().length)}>
  How many?
</button>

The reverse direction - write a cell - is also on SvGridApi:

api.setCellValue(rowIndex, columnId, value)
const v = api.getCellValue(rowIndex, columnId)

2. From the row model (post-pipeline)

For the rows the grid is rendering (after sort + filter + grouping + pagination), you need the headless grid instance. The wrapper does not expose it as a prop today; if you need post-pipeline access, instantiate the headless engine yourself with createSvGrid and pass its computed output into your own renderer. See packages/grid/src/createGrid.svelte.ts.

A dedicated api.getDisplayedRows() is on the gap list.

3. From the source data directly

In most apps the cleanest path is "the parent owns the data array, the grid reflects it". When you need to know what's in the grid, look at your own state - not the grid.

<script lang="ts">
  let rows = $state<Person[]>([])
</script>

<SvGrid data={rows} {columns} features={{}} />

<p>{rows.length} rows total.</p>

This works because data passed to <SvGrid> is treated as the authoritative source - the grid never silently mutates it.

Iterating

const data = api?.getData() ?? []
for (const row of data) {
  // ...
}

For thousands of rows in a hot loop, prefer indexed iteration:

const data = api!.getData()
for (let i = 0; i < data.length; i++) {
  const row = data[i]!
  // ...
}

Source rows versus displayed rows

getData returns what you handed the grid. getDisplayedRows returns what survived the filter and the sort. Confusing the two is behind most wrong export counts and most "select all" bugs.

<script lang="ts">
  import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'

  type Person = {
    id: number
    name: string
    department: string
    city: string
    salary: number
    bio: string
  }

  const seed: Person[] = [
    { id: 1, name: 'Ada Lovelace',   department: 'Engineering', city: 'London',   salary: 142000,
      bio: 'Wrote the first algorithm intended for a machine, and the first account of what a general-purpose computer could do beyond arithmetic.' },
    { id: 2, name: 'Grace Hopper',   department: 'Engineering', city: 'New York', salary: 168000,
      bio: 'Built the first compiler and argued that programs should be written in something closer to English than to machine code.' },
    { id: 3, name: 'Linus Torvalds', department: 'Platform',    city: 'Portland', salary: 155000,
      bio: 'Wrote a kernel and, later, the version control system that most of the industry now runs on.' },
  ]

  let api = $state<SvGridApi<{}, Person> | null>(null)
  let counts = $state('(filter something, then read)')

  const columns: GridColumns<Person> = [
    { field: 'name',       header: 'Name',       width: 190 },
    { field: 'department', header: 'Department', width: 170 },
  ]

  function read() {
    const all = api?.getData() ?? []
    const shown = api?.getDisplayedRows() ?? []
    counts = 'source ' + all.length + ', displayed ' + shown.length
  }
</script>

<button type="button" onclick={read}>Compare</button>

<SvGrid data={seed} {columns} filterable filterMode="row" sortable onApiReady={(next) => (api = next)} />

<p>{counts}</p>

Reaching one row by id

Once getRowId is set, a row is addressable by something stable rather than by where it currently sits. Sort the grid first and the lookup still finds the same person, which is the whole reason to bother with an id.

<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 api = $state<SvGridApi<{}, Person> | null>(null)
  let found = $state('(nothing looked up)')

  const columns: GridColumns<Person> = [
    { field: 'id',   header: 'ID',   width: 80 },
    { field: 'name', header: 'Name', width: 190 },
    { field: 'city', header: 'City', width: 150 },
  ]

  function lookup(id: string) {
    const row = (api?.getData() ?? []).find((r) => String(r.id) === id)
    found = row ? row.name + ' - ' + row.city : 'no row with id ' + id
  }
</script>

<div>
  <button type="button" onclick={() => lookup('2')}>Find id 2</button>
  <button type="button" onclick={() => lookup('9')}>Find id 9</button>
</div>

<SvGrid data={seed} {columns} getRowId={(r) => String(r.id)} sortable onApiReady={(next) => (api = next)} />

<p>{found}</p>

See also