Row pagination
Pagination is opt-in: pageable turns it on (the longer showPagination
does the same) and pageSize sets the slice. <SvGrid> pages its rows
itself, so there is nothing else to register. rowPaginationFeature and
createPaginatedRowModel are for the headless engine, where the row model
goes in _rowModels.paginatedRowModel of createSvGridCore (see
Row models); <SvGrid> has no options prop
to pass them through.
Open the live example: Sort, filter, paginate (Filtering & Search)
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
email: string
department: string
age: number
salary: number
city: string
startDate: string
active: boolean
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', email: '[email protected]', department: 'Engineering', age: 36, salary: 142000, city: 'London', startDate: '2021-03-01', active: true },
{ id: 2, name: 'Grace Hopper', email: '[email protected]', department: 'Engineering', age: 45, salary: 168000, city: 'New York', startDate: '2019-07-15', active: true },
{ id: 3, name: 'Linus Torvalds', email: '[email protected]', department: 'Platform', age: 54, salary: 155000, city: 'Portland', startDate: '2020-01-20', active: false },
{ id: 4, name: 'Radia Perlman', email: '[email protected]', department: 'Networking', age: 49, salary: 161000, city: 'Seattle', startDate: '2022-09-05', active: true },
{ id: 5, name: 'Barbara Liskov', email: '[email protected]', department: 'Platform', age: 52, salary: 172000, city: 'Boston', startDate: '2018-11-11', active: true },
]
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>
<SvGrid {data} {columns} pageable />
The wrapper renders a footer with page nav and a page-size selector.
Set the initial page size
<SvGrid
data={rows}
columns={columns}
features={features}
showPagination={true}
pageSize={25}
/>
The wrapper's footer renders 10 / 25 / 50 / 100 in the size selector
and lets the user change it at runtime. Jumping to a page from outside
is best done by hiding the built-in footer (showPagination={false})
and rendering your own controls - see the
09-server-side demo
for the canonical pattern. A server-side fetcher keeps the footer: hand
createServerDataSource to the grid as rowModel and the pager reads the
server's count and drives the controller's setPage - see
Server paging.
Page size
The default is 10 unless you pass pageSize. The footer's size
selector picks 10 / 25 / 50 / 100; pass a different pageSize to seed
a different initial value.
Pagination + virtualization
These two work together but they solve different problems. Use virtualization when the page itself is large (>200 rows); use pagination when you want explicit pages, when the user prints/exports, or when server-side fetch returns pages.
For 100k-row + virtualized examples, pagination is off and the whole filtered set is scrollable - see demos/06-large-dataset.svelte.
Try it
pageable turns the footer on and pageSize sets the slice. Sorting and
filtering run before pagination, so page 1 is always the first rows of the
result rather than the first rows of your array.
<SvGrid data={people} {columns} pageable pageSize={2} sortable filterable />
Go to the page a row is on
api.getRowPosition(id) is where a row sits in the filtered, sorted rows
across every page, or null when a filter hides it. Divide by the page size
and api.setPage turns to that page, whatever order the user has sorted
into. The id is the one getRowId returns. With grouping, pages are counted
in groups and the division does not hold.
<script lang="ts">
import { SvGrid, type SvGridApi } from '@svgrid/grid'
let api = $state<SvGridApi<{}, Person> | null>(null)
function showRow(id: string) {
const position = api?.getRowPosition(id)
if (api && position != null) api.setPage(Math.floor(position / api.getPageInfo().pageSize))
}
</script>
<button onclick={() => showRow('4')}>Show Radia Perlman</button>
<SvGrid data={people} {columns} pageable pageSize={2} sortable getRowId={(r) => String(r.id)} onApiReady={(next) => (api = next)} />
api.getPageInfo() also returns pageIndex and pageCount, and
api.setPageSize(n) changes the slice from code.
See also
Live examples
- Sort, filter, paginate - Three most-asked-for features wired together against ~5k rows.
- Server-side data - Sort/filter/page round-tripped to a mock endpoint with debounce + cancel.
- 100k rows × 100 columns - Row + column virtualization. Chunked load with progress + cancellation.
Related articles
- Pagination Patterns - Offset, Cursor, and Infinite Scroll - A practical breakdown of offset, cursor, and infinite-scroll pagination for SvGrid - when each pattern fits, how to wire it, and where each one breaks.