Data

Pagination

Client paging with a footer that counts, plus the two hooks a server row model needs. Pagination is a windowing stage, so it runs last, over rows that filtering and sorting have already settled.

Basic Usage

The footer shows the range, the total and a page-size select. Filter the grid and watch both the total and the page reset.

page 1 of 8 60 rows
Email
Hoang Kowalski
hoang.kowalski1@example.com
Design
$127,691.00
Bruno Nguyen
bruno.nguyen2@example.com
Growth
$105,146.00
Bruno Dubois
bruno.dubois3@example.com
Design
$86,538.00
Farid Haddad
farid.haddad4@example.com
Growth
$76,443.00
Jonas Yilmaz
jonas.yilmaz5@example.com
Core
$129,812.00
Quyen Tanaka
quyen.tanaka6@example.com
Growth
$72,011.00
Mai Nguyen
mai.nguyen7@example.com
Support
$83,226.00
Bruno Novak
bruno.novak8@example.com
Support
$71,507.00
60 rows
1–8 of 60
<!-- pageSize is all pagination needs in the shorthand form -->
<DataGrid data={people} {columns} {getRowId} pageSize={8} toolbar />

<script lang="ts">
  import { createDataGrid, pagination } from '@sv5ui/datagrid';

  // Registered by hand, with a starting page
  const grid = createDataGrid<Person>({
    data: people,
    columns,
    getRowId,
    features: [pagination({ pageSize: 8, page: 2 })]
  });
</script>

Choosing the Page Sizes

Compose the chrome yourself when the default footer is not what you want. The status bar and the footer are separate parts, so either can be dropped or moved.

Email
Hoang Kowalski
hoang.kowalski1@example.com
Design
Bruno Nguyen
bruno.nguyen2@example.com
Growth
Bruno Dubois
bruno.dubois3@example.com
Design
Farid Haddad
farid.haddad4@example.com
Growth
Jonas Yilmaz
jonas.yilmaz5@example.com
Core
24 rows
1–5 of 24
<!-- The footer comes with DataGrid. Compose it yourself to choose the
     page-size options or to put it somewhere else. -->
<Grid.Root {grid}>
  <Grid.Viewport>
    <Grid.Header />
    <Grid.Body />
  </Grid.Viewport>

  <Grid.StatusBar />
  <Grid.Pagination pageSizes={[5, 10, 25]} />
</Grid.Root>

Resets and Clamping

Sorting or filtering returns the grid to page 1, because page 7 of a list the user has just narrowed is nowhere in particular. The page is also clamped when it is read rather than when it is set, so rows disappearing underneath it can never strand anyone on an empty page.

Press the buttons in order. Page 6 of 6 becomes page 1 of 2 the moment the filter lands, and the badge shows the page the grid reports rather than the one it was last told.

page 1 of 6
Email
Hoang Kowalski
hoang.kowalski1@example.com
Design
Bruno Nguyen
bruno.nguyen2@example.com
Growth
Bruno Dubois
bruno.dubois3@example.com
Design
Farid Haddad
farid.haddad4@example.com
Growth
Jonas Yilmaz
jonas.yilmaz5@example.com
Core
30 rows
1–5 of 30
// Sorting or filtering sends the grid back to page 1, because page 7 of
// a list the user has just narrowed is nowhere in particular.
grid.events.on('sortChanged', () => {/* page is already 1 */});
grid.events.on('filterChanged', () => {/* page is already 1 */});

// The page also clamps on read rather than on write: rows can disappear
// without going through setPage, and a page past the end would strand the
// user on empty rows.

Driving the Pages

Page size is a preference and is persisted; the page number is not, because restoring page 7 of a list the user has since filtered lands them nowhere. The grid below has no footer at all, so every move comes from a call.

page 1 of 5, 4 per page
Email
Hoang Kowalski
hoang.kowalski1@example.com
Design
Bruno Nguyen
bruno.nguyen2@example.com
Growth
Bruno Dubois
bruno.dubois3@example.com
Design
Farid Haddad
farid.haddad4@example.com
Growth
import { getPagination } from '@sv5ui/datagrid';

const paging = getPagination(grid);

paging?.page;       // clamped on read, so it never points past the end
paging?.pageSize;   // number, or null for "everything on one page"
paging?.pageCount;
paging?.total;      // rowCount when set, otherwise grid.totalRows
paging?.server;     // true when rowModel is 'server'

paging?.setPage(3);
paging?.setPageSize(25);
paging?.setPageSize(null);   // one page, no slicing
paging?.setRowCount(1042);   // what the server says the total is

// The same three through grid.api
grid.api.setPage?.(3);
grid.api.setPageSize?.(25);
grid.api.setRowCount?.(1042);

grid.events.on('pageChanged', ({ page, pageSize }) => console.log(page, pageSize));

Server Paging

Under rowModel: 'server' the windowing stage passes rows through untouched, because data already holds one page. The feature stays registered, because its state and its footer are what the fetch listens to.

setRowCount is what makes the footer count against the whole set rather than the page in hand.

import { createDataGrid, filtering, pagination, sorting } from '@sv5ui/datagrid';

// data holds exactly one page; the pipeline passes it through untouched
const grid = createDataGrid<Person>({
  columns,
  data: [],
  getRowId,
  rowModel: 'server',
  features: [sorting(), filtering(), pagination({ pageSize: 25 })]
});

for (const event of ['sortChanged', 'filterChanged', 'pageChanged'] as const) {
  grid.events.on(event, fetchPage);
}

async function fetchPage() {
  const { rows, total } = await api.load({ /* ... */ });
  grid.data = rows;
  grid.api.setRowCount(total);   // what the footer counts against
}

Pagination or Virtualization

One window-order feature per grid. The constructor throws rather than letting two stages fight over the same slice.

// Both features claim the windowing stage of the pipeline, so registering
// both throws when the grid is constructed:
//
//   Only one window-order feature may be registered
//
createDataGrid<Person>({
  columns, data, getRowId,
  features: [pagination(), virtualization()]   // throws
});

// Pick one per grid. Pagination suits a page of records; virtualization
// suits a scrollable list that keeps going.

pagination() Options

OptionDefault
pageSizenull
page1
rowCountnull

Pagination State

What getPagination(grid) exposes. The three setters are also merged into grid.api.

MemberDescription
pageThe current page, clamped on read so it never points past the end
pageSizeRows per page
pageCountHow many pages the total divides into
totalrowCount when a server set it, otherwise the filtered row count
serverTrue when the grid's rowModel is 'server'
setPage(n)Clamps into range and emits pageChanged
setPageSize(n)Also returns to page 1
setRowCount(n)What the footer counts against under a server row model

Grid.Pagination Props

PropTypeDefault
pageSizesnumber[][10, 25, 50, 100]
classClassNameValue-