shadcn.io is an independent project built on shadcn/ui
Page numbers, with previous and next, sit under a long list. The current page is marked.
Use it when a collection doesn't fit in one view. The path through the site is a Breadcrumb, not more pages of the same list. In React, React Aria renders a navigation landmark, and each page should keep its own address.
Installation
Anatomy

Pagination
โโโ PaginationItem
โโโ PaginationEllipsis
โโโ PaginationFirstTrigger
โโโ PaginationPrevious
โโโ PaginationNext
โโโ PaginationLastTriggerUsage
import {
Pagination, PaginationContent, PaginationEllipsis, PaginationItem,
PaginationLink, PaginationNext, PaginationPrevious,
} from "@/components/ui/pagination";<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>
2
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>Accessibility
- Enter
- Activate the focused control.
- Space
- Activate the focused control.
Demos
Simple
Five page links and nothing else, with the current one marked isActive. Use a numbers-only row when there are few pages and a previous or next control would only widen it. Once the list runs long, add those ends and an ellipsis, which is the opening preview. isActive is also how assistive tech knows which page is current.
Icons Only
Previous and next, with no numbers, beside a rows-per-page Select. That is the compact footer of a data table, where stepping matters more than jumping. Use it when the table already shows a range and numbered links would repeat it. Keep the numbers when someone may need a far page, because stepping one page at a time is a poor way to get there.
Rtl
dir="rtl" flips the row, and text on previous and next replaces the English words with Arabic labels. The arrows follow the reading order, so previous stays at the start. Pass text whenever the visible word is not the default, because that string is also the accessible name. Numbers in the same script belong in this row too.
FAQ
How do I track the current page with the React Aria Pagination?
It's presentational: keep the current page in your state or in the URL, render the PaginationLinks around it yourself, and mark the current one with isActive.
How do I use Next.js Link or my router with Pagination in React?
Keep a real URL per page, so people can bookmark page 12 and search engines can follow it.
PaginationLink is React Aria's Link: wrap your app in React Aria's RouterProvider with your router's navigate, and every href routes on the client.
How do I show an ellipsis when Pagination has many pages?
Render the first and last pages, the current page's neighbors, and a PaginationEllipsis in each gap, rather than a link for every page.
Why can I still click Previous on the first page?
Pagination doesn't know your page count. Leave PaginationPrevious out on page 1 and PaginationNext out on the last page.
How do I show only Previous and Next buttons in Pagination?
Leave out the numbered PaginationLinks and keep PaginationPrevious and PaginationNext. The Icons Only demo above does that, with a rows-per-page Select beside them.
How do I change or translate the Pagination labels?
Pass text on PaginationPrevious and PaginationNext ("Previous" and "Next" by default). For a right-to-left language, set the direction too, as in the RTL demo, so the row and its arrows follow the reading order.
API Reference
Pagination
<nav> data-slot="pagination"
className?string
Merged with the part's classes.
PaginationContent
<ul> data-slot="pagination-content"
className?string
Merged with the part's classes.
PaginationItem
data-slot="pagination-item"
PaginationLink
data-slot="pagination-link"
isActive?boolean
Marks the link as the current page: outlined, and aria-current="page".
size?"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"
Ark default: md.
- Type
"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"- Default
"icon-md"
className?string
Merged with the part's classes.
data-active?string
Mirrors isActive.
PaginationPrevious
isActive?boolean
Marks the link as the current page: outlined, and aria-current="page".
size?"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"
Ark default: md.
- Type
"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"- Default
md
text?string
The button's label, beside its arrow.
- Default
"Previous"
className?string
Merged with the part's classes.
data-icon"inline-start"
- Default
"inline-start"
PaginationNext
isActive?boolean
Marks the link as the current page: outlined, and aria-current="page".
size?"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"
Ark default: md.
- Type
"default" | "icon" | "icon-lg" | "icon-md" | "icon-sm" | "icon-xl" | "icon-xs" | "lg" | "md" | "sm" | "xl" | "xs"- Default
md
text?string
The button's label, beside its arrow.
- Default
"Next"
className?string
Merged with the part's classes.
data-icon"inline-end"
- Default
"inline-end"
PaginationEllipsis
<span> data-slot="pagination-ellipsis"
className?string
Merged with the part's classes.











