Skip to main content

Pagination

Pager with previous/next and a page list. Fully controlled from parent state.

Quick start
import { Pagination } from "mates-ui";

Pagination({ currentPage: 1, totalPages: 10, onChange: (p) => {} });

Few pages

import { html, atom, renderApp } from 'mates';
import { Pagination, Text } from 'mates-ui';

const App = () => {
const page = atom(1);
return () => html`
<x-col gap="var(--md-space-3)">
${Text("Current: " + page(), { type: "body-sm", color: "muted" })}
${Pagination({ currentPage: page(), totalPages: 7, onChange: (p) => page.set(p) })}
</x-col>
`;
};

renderApp(App, document.getElementById('app'));

Many pages with ellipsis

import { html, atom, renderApp } from 'mates';
import { Pagination, Text } from 'mates-ui';

const App = () => {
const page = atom(5);
return () => html`
<x-col gap="var(--md-space-3)">
${Text("Current: " + page(), { type: "body-sm", color: "muted" })}
${Pagination({ currentPage: page(), totalPages: 24, siblingCount: 1, onChange: (p) => page.set(p) })}
</x-col>
`;
};

renderApp(App, document.getElementById('app'));

Wide sibling window

import { html, renderApp } from 'mates';
import { Pagination } from 'mates-ui';

const App = () => () => html`
${Pagination({ currentPage: 8, totalPages: 30, siblingCount: 2, disabled: true, onChange: () => {} })}
`;

renderApp(App, document.getElementById('app'));

Edge cases — 0 and 1 pages

import { html, renderApp } from 'mates';
import { Pagination, Text } from 'mates-ui';

const App = () => () => html`
<x-col gap="var(--md-space-4)">
<x-col gap="var(--md-space-2)">
${Text("totalPages: 0 — nothing rendered", { type: "label-sm", color: "muted" })}
${Pagination({ currentPage: 1, totalPages: 0, onChange: () => {} })}
</x-col>
<x-col gap="var(--md-space-2)">
${Text("totalPages: 1 — nothing rendered", { type: "label-sm", color: "muted" })}
${Pagination({ currentPage: 1, totalPages: 1, onChange: () => {} })}
</x-col>
</x-col>
`;

renderApp(App, document.getElementById('app'));

Pagination

import { Pagination } from "mates-ui";
Prop Type Default Description
attr AttrMap Extra HTML attributes forwarded to the root element.
classes string | string[] Extra root classes — joined and appended after built-in classes.
currentPage* number The currently active page (1-based).
data DataAttrMap Root `data-*` map (`testId` → `data-testid`). `testId` prop / `attr` win over `data`.
disabled boolean false Disables all interactive controls.
id string Root `id` shorthand (`attr.id` wins). Form native-control `id` props are unchanged.
onChange* (page: number) => void Called with the new page number when a page button or prev/next is clicked.
siblingCount number 1 Number of page buttons shown on each side of the current page before an ellipsis is inserted.
totalPages* number Total number of pages. Renders nothing when 0 or 1.

CSS tokens

Token Role
--md-color-on-primary Text colour of the active page button.
--md-color-primary Background of the active page button.
--md-color-surface-raised Background of inactive page buttons.
--md-shape-full Border-radius giving buttons a pill shape.

Caveats

  • When `totalPages` is 0 or 1, no pagination is rendered.
  • `currentPage` is 1-based.
  • Always update `currentPage` in `onChange` — Pagination is fully controlled.