UI.MD

Pagination

A pager for a table, a card grid, or any list: numbered pages, prev and next, a row count, and an optional rows-per-page select.

Installation

$
npx shadcn@latest add https://ui.mattdowney.com/r/pagination.json

Usage

import { Pagination } from "@/components/ui/pagination"

Examples

Default

Page numbers with the current one filled. Pages either side of it stay visible and the rest collapse to an ellipsis, so the row is the same length on page 2 as on page 40 and nothing beside it shifts as you move.

Under a table

The count and the rows-per-page control take the table's left edge, the pager takes its right. The select needs no visible label: it reads "10 per page" on its own. Changing the size sends you back to page 1, since page 9 of 47 rows stops existing at 25 per page.

OrderCustomerTotal
ORD-4820Alex Rivera$180
ORD-4821Dana Cole$217
ORD-4822Sam Okafor$254
ORD-4823Priya Nair$291
ORD-4824Alex Rivera$328

Under anything else

Nothing about this is table-shaped. With no count and no page size beside it the pager is the whole row, so it centers under the grid it belongs to.

Sam OkaforORD-4826 · $402
Priya NairORD-4827 · $439
Alex RiveraORD-4828 · $476
Dana ColeORD-4829 · $513
Sam OkaforORD-4830 · $550
Priya NairORD-4831 · $587

Paging by URL

Return the element each page should render as and the pager draws links instead of buttons, which is what a Server Component needs: it cannot hand a click handler to a button, but it can build a link. The two bounds stay buttons, since a link has no disabled state to give them.

Siblings

How many pages stay visible either side of the current one: 0, 1, and 2. Every value keeps its own row length fixed, so this is a density choice, not a behavior one.

API Reference

PropTypeDefaultDescription
page*number-The current page, 1-based.
pageCount*number-How many pages there are in total.
onPageChange(page: number) => void-Called with the page that was clicked. Omit it for link paging (renderPage); the pager only builds a click handler when it was given one.
siblingsnumber1How many pages to show either side of the current one. The first and last page are always shown, so the row holds siblings * 2 + 5 controls at every page.
totalnumber-Total number of rows. With pageSize, renders the "1-10 of 240" count. A total of 0 reads "No results".
pageSizenumber-Rows per page. Needed for the count, and it is the current value of the size select.
pageSizeOptionsnumber[]-Offering these renders the rows-per-page select. Needs onPageSizeChange.
onPageSizeChange(pageSize: number) => void-Called with the newly chosen page size. Send the user back to page 1 here.
renderPage(page: number) => ReactElement-For URL paging: return the element a page control should render as, e.g. (page) => <Link href={?page=${page}} />. It takes the button's styling and its label.