Pagination
A pager that never changes width, with a sliding marker, arrow keys, and a compact jump-to-page form.
31–40 of 1,284 invoices
Installation
npx shadcn@latest add @quireui/paginationUsage
<Pagination page={page} pageCount={129} onPageChange={setPage} />A pager that stays put
The pager always shows the same seven slots: the first and last page, the current page with one on each side, and a gap wherever pages are skipped. Every slot is as wide as the longest page number. So the pager never changes width while you page, and the next button never moves away from your cursor.
The marker slides to the current page. Paging through the middle, it stays in the centre and the numbers change around it.
Links or buttons
With onPageChange the pages are buttons, for paging in place. Add getHref and they become real links, so a page can be opened in a new tab, shared or crawled; with both, a plain click still pages in place.
<Pagination page={page} pageCount={20} getHref={(p) => `?page=${p}`} onPageChange={setPage} />Loading
When the next page comes from a server, pass loading while it is on its way. The marker has already moved, so the click feels answered; a thin line runs inside it if loading takes longer than 150ms, so fast pages never flicker. With a transition it costs nothing:
const [isPending, startTransition] = useTransition();
<Pagination
page={page}
pageCount={pageCount}
onPageChange={(next) => startTransition(() => setPage(next))}
loading={isPending}
/>In the first example, the old rows stay, dimmed, until the new page arrives. That is calmer than flashing skeletons for a page that loads in half a second; keep Skeleton for the first load.
Compact
variant="compact" shows "Page 37 of 129" with a field to type a page into, for long lists where the numbers would tell you little. Arrow up and down in the field step a page.
Summary and page size
PaginationSummary says where the visible rows sit, like "31–40 of 1,284 invoices", and is announced politely when it changes. PaginationPageSize is a small select for rows per page. In this example, changing the page size keeps the first visible row in view instead of jumping back to page one.
31–40 of 1,284 invoices
Accessibility
The pager is a nav landmark named "Pagination". The current page is marked aria-current="page", every page button says which page it opens, and the pager is marked busy while loading. PaginationSummary is announced politely when it changes.
| Key | Action |
|---|---|
| ← / → | With focus in the pager, goes to the previous or next page. Focus follows the current page. |
| Home / End | Goes to the first or last page. |
| Enter | In the compact field, goes to the typed page. |
| ↑ / ↓ | In the compact field, steps one page. |
Motion
The marker slides in 160ms. From the keyboard it moves instantly, so arrowing through pages never waits on an animation.
API reference
Pagination
Prop
Type
Also takes every <nav> attribute. Style it with [data-slot="pagination"].
PaginationSummary
"31–40 of 1,284 invoices": where the visible rows sit in the whole set.
Prop
Type
Also takes every <p> attribute. Style it with [data-slot="pagination-summary"].
PaginationPageSize
How many rows per page.
Prop
Type