Pagination
Moves through a long list one page at a time and shows where people are in it. Page numbers are links for pages a search engine should find, or buttons for a list that lives in the browser.
Installation
Set up Camaleo once (Installation), then import what you need. DataTable already includes it; use it on its own for any other list.
import { Pagination } from "@camaleo/react";Anatomy
A nav landmark around a list. The first and last items are Previous and Next; between them, the page numbers and the gaps. The number of items stays the same as the page changes, so the control doesn't jump in width.
Examples
Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.
Links, for pages people can share
Pass getHref when each page has its own URL: search engines follow the links, and people can open a page in a new tab or share it.
Recent orders
- #4821$49.90Maya ChenPaid
- #4820$87.69Daniel OkaforPaid
- #4819$125.48Sofia RamirezPending
- #4818$163.27Liam BeckerPaid
A list in the browser
Change the page. With onPageChange the numbers are buttons; focus stays on the one you pressed, and a status message says "Page 3 of 10".
Compact, for phones
With text arrows and one sibling, the row wraps to two lines below about 420px. siblings={0} and the arrows' names in VisuallyHidden keep it under 310px in every skin, one line on a 390px phone; the total moves to the text above.
With page size and a count
Change the rows per page. "Showing 21–40 of 312" says how much there is, and the new page keeps the first row you were looking at.
First and last always there
The first and last pages never leave the row, so a single press goes back to the start or straight to the end of 48 pages.
siblings=0siblings=1siblings=2Siblings
siblings sets how many pages show on each side of the current one. Use 0 in narrow places, 2 when people tend to jump a few pages.
Names for screen readers
Translate aria-label, the arrows and pageLabel. Including the total in pageLabel makes each number read "Page 3 of 12".
In context
These are whole pieces of UI you can copy, in the skin you picked.
Blog archive
- Product10/21/2026Pix refunds now arrive in seconds
- Design10/08/2026How we built dark mode for 13 skins
- Engineering09/30/2026Checkout is 40% faster on phones
Recent orders
| Order | Customer | Status | Total |
|---|---|---|---|
| #5132 | Maya Chen | Paid | $49.90 |
| #5131 | Daniel Okafor | Paid | $87.69 |
| #5130 | Sofia Ramirez | Pending | $125.48 |
| #5129 | Liam Becker | Paid | $163.27 |
| #5128 | Aisha Patel | Paid | $201.06 |
- How to refund an orderFull refunds go back to the original payment method in 5 to 10 business days.
- Responding to a chargebackSend proof of delivery within 7 days so the bank can review the dispute.
- Partial refunds and store creditRefund part of an order or give credit the customer can use on their next purchase.
Guidelines
The current page and "Showing 21–40 of 312" answer both questions before anyone asks.
Without a page number or a total, people can't tell how far they've gone or how much is left.
- Ana Ribeiro
- Carlos Mendes
- Júlia Santos
- Pedro Almeida
- Beatriz Costa
Five names fit on the screen. Reading them takes less time than finding the next page.
- Ana Ribeiro
- Carlos Mendes
Three pages of two names hide most of the list behind clicks, and Ctrl+F stops finding them.
Props
onPageChange.Other props go to the nav. Give either getHref (links) or onPageChange (buttons).
Styling hooks
Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the pagination itself.
Attributes
Tokens it reads
Color
Shape & size
Type & motion
This component only
/* square page numbers in the orders table */
.orders [data-slot="pagination-item"] {
--cml-radius-control: 4px;
}Accessibility
- It is a nav landmark. Name it after what it pages through ("Order pages") and make the name unique when a page has two.
- The current page has aria-current="page". Each number is named by pageLabel, "Page 3" by default; the … gaps are hidden from screen readers.
- With onPageChange, focus stays on the control that was pressed, so people can keep paging. Announce the change in a role="status" message ("Page 3 of 12"); the updated list is right above.
- With getHref, each page is a new URL and a full page load; let the page's title say which page it is ("Orders, page 3 of 12").