apps/docs/content/docs/react/migration/(components)/pagination.mdx
In v2, Pagination was a single component that handled all rendering internally via props:
import { Pagination } from "@heroui/react";
export default function App() {
return (
<Pagination total={10} initialPage={1} showControls />
);
}
In v3, Pagination uses a compound component pattern where you compose each part explicitly:
import { Pagination } from "@heroui/react";
export default function App() {
return (
<Pagination>
<Pagination.Content>
<Pagination.Item>
<Pagination.Previous>
<Pagination.PreviousIcon />
</Pagination.Previous>
</Pagination.Item>
<Pagination.Item>
<Pagination.Link isActive>1</Pagination.Link>
</Pagination.Item>
<Pagination.Item>
<Pagination.Link>2</Pagination.Link>
</Pagination.Item>
<Pagination.Item>
<Pagination.Link>3</Pagination.Link>
</Pagination.Item>
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
<Pagination.Item>
<Pagination.Link>10</Pagination.Link>
</Pagination.Item>
<Pagination.Item>
<Pagination.Next>
<Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
);
}
v2: Single Pagination component that auto-generates page items from total prop
v3: Compound components: Pagination, Pagination.Summary, Pagination.Content, Pagination.Item, Pagination.Link, Pagination.Previous, Pagination.PreviousIcon, Pagination.Next, Pagination.NextIcon, Pagination.Ellipsis
v2: Pages auto-generated from total, siblings, boundaries props
v3: You compose page items manually, giving full control over layout and behavior. Build your own pagination logic or use a pagination hook.
| v2 Prop | v3 Equivalent | Notes |
|---|---|---|
total | - | Removed (compose items manually) |
page | - | Manage active state via isActive on Pagination.Link |
initialPage | - | Manage state externally |
onChange | - | Use onPress on individual Pagination.Link components |
siblings | - | Removed (compose items manually) |
boundaries | - | Removed (compose items manually) |
dotsJump | - | Removed (handle ellipsis click manually) |
loop | - | Removed (implement manually) |
showControls | - | Compose Pagination.Previous and Pagination.Next |
isCompact | - | Removed (style with Tailwind CSS) |
showShadow | - | Removed (use Tailwind shadow-* classes) |
size | Pagination size | Same (sm, md, lg) |
variant | - | Removed (use Tailwind CSS) |
color | - | Removed (use Tailwind CSS) |
radius | - | Removed (use Tailwind CSS) |
isDisabled | isDisabled on Pagination.Link, Pagination.Previous, Pagination.Next | Per-item instead of global |
disableCursorAnimation | - | Removed |
disableAnimation | - | Removed |
renderItem | - | Compose items directly |
getItemAriaLabel | - | Set aria-label on individual items |
classNames | - | Use className on individual compound components |
v2: usePagination hook available for custom implementations
v3: No built-in hook — compose pagination items directly or build your own pagination logic
<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { Pagination } from "@heroui/react";
<Pagination total={10} initialPage={1} />
```
const [page, setPage] = useState(1);
const totalPages = 10;
<Pagination>
<Pagination.Content>
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
<Pagination.Item key={p}>
<Pagination.Link isActive={page === p} onPress={() => setPage(p)}>
{p}
</Pagination.Link>
</Pagination.Item>
))}
</Pagination.Content>
</Pagination>
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx <Pagination total={10} initialPage={1} showControls />
</Tab>
<Tab value="v3">
```tsx
const [page, setPage] = useState(1);
const totalPages = 10;
<Pagination>
<Pagination.Content>
<Pagination.Item>
<Pagination.Previous
isDisabled={page === 1}
onPress={() => setPage((p) => Math.max(1, p - 1))}
>
<Pagination.PreviousIcon />
</Pagination.Previous>
</Pagination.Item>
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => (
<Pagination.Item key={p}>
<Pagination.Link isActive={page === p} onPress={() => setPage(p)}>
{p}
</Pagination.Link>
</Pagination.Item>
))}
<Pagination.Item>
<Pagination.Next
isDisabled={page === totalPages}
onPress={() => setPage((p) => Math.min(totalPages, p + 1))}
>
<Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx <Pagination total={20} initialPage={1} siblings={1} boundaries={1} />
</Tab>
<Tab value="v3">
```tsx
const [page, setPage] = useState(1);
const totalPages = 20;
<Pagination>
<Pagination.Content>
<Pagination.Item>
<Pagination.Previous
isDisabled={page === 1}
onPress={() => setPage((p) => Math.max(1, p - 1))}
>
<Pagination.PreviousIcon />
</Pagination.Previous>
</Pagination.Item>
<Pagination.Item>
<Pagination.Link isActive={page === 1} onPress={() => setPage(1)}>
1
</Pagination.Link>
</Pagination.Item>
{page > 3 && (
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
)}
{[page - 1, page, page + 1]
.filter((p) => p > 1 && p < totalPages)
.map((p) => (
<Pagination.Item key={p}>
<Pagination.Link isActive={page === p} onPress={() => setPage(p)}>
{p}
</Pagination.Link>
</Pagination.Item>
))}
{page < totalPages - 2 && (
<Pagination.Item>
<Pagination.Ellipsis />
</Pagination.Item>
)}
<Pagination.Item>
<Pagination.Link
isActive={page === totalPages}
onPress={() => setPage(totalPages)}
>
{totalPages}
</Pagination.Link>
</Pagination.Item>
<Pagination.Item>
<Pagination.Next
isDisabled={page === totalPages}
onPress={() => setPage((p) => Math.min(totalPages, p + 1))}
>
<Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx
</Tab>
<Tab value="v3">
```tsx
const [page, setPage] = useState(1);
const totalPages = 10;
<Pagination>
<Pagination.Content>
<Pagination.Item>
<Pagination.Previous
isDisabled={page === 1}
onPress={() => setPage((p) => p - 1)}
>
<Pagination.PreviousIcon />
<span>Previous</span>
</Pagination.Previous>
</Pagination.Item>
<Pagination.Item>
<Pagination.Next
isDisabled={page === totalPages}
onPress={() => setPage((p) => p + 1)}
>
<span>Next</span>
<Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx
</Tab>
<Tab value="v3">
```tsx
const [page, setPage] = useState(1);
const perPage = 10;
const total = 100;
<Pagination>
<Pagination.Summary>
Showing {(page - 1) * perPage + 1}-{Math.min(page * perPage, total)} of {total}
</Pagination.Summary>
<Pagination.Content>
</Pagination.Content>
</Pagination>
```
<Tabs items={["v2", "v3"]}>
<Tab value="v2">
tsx
</Tab>
<Tab value="v3">
```tsx
import { Icon } from "@iconify/react";
<Pagination>
<Pagination.Content>
<Pagination.Item>
<Pagination.Previous onPress={() => setPage((p) => p - 1)}>
<Pagination.PreviousIcon>
<Icon icon="gravity-ui:arrow-left" />
</Pagination.PreviousIcon>
</Pagination.Previous>
</Pagination.Item>
<Pagination.Item>
<Pagination.Next onPress={() => setPage((p) => p + 1)}>
<Pagination.NextIcon>
<Icon icon="gravity-ui:arrow-right" />
</Pagination.NextIcon>
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
```
classNames Prop<Pagination
classNames={{
base: "custom-base",
wrapper: "custom-wrapper",
prev: "custom-prev",
next: "custom-next",
item: "custom-item",
cursor: "custom-cursor",
ellipsis: "custom-ellipsis",
}}
/>
className Props<Pagination className="custom-base">
<Pagination.Content className="custom-wrapper">
<Pagination.Item className="custom-item">
<Pagination.Previous className="custom-prev">
<Pagination.PreviousIcon />
</Pagination.Previous>
</Pagination.Item>
<Pagination.Item>
<Pagination.Link isActive className="custom-cursor">1</Pagination.Link>
</Pagination.Item>
<Pagination.Item>
<Pagination.Ellipsis className="custom-ellipsis" />
</Pagination.Item>
<Pagination.Item>
<Pagination.Next className="custom-next">
<Pagination.NextIcon />
</Pagination.Next>
</Pagination.Item>
</Pagination.Content>
</Pagination>
The v3 Pagination follows this structure:
Pagination (Root, nav element)
├── Pagination.Summary (optional, info text)
└── Pagination.Content (ul container)
└── Pagination.Item (li wrapper, repeated)
├── Pagination.Previous (with Pagination.PreviousIcon)
├── Pagination.Link (page number, isActive for current)
├── Pagination.Ellipsis
└── Pagination.Next (with Pagination.NextIcon)
total/siblings/boundaries props → compose page items manually with your own pagination logicpage/initialPage props → isActive prop on individual Pagination.LinkshowControls prop → compose Pagination.Previous and Pagination.Next directlyPagination.Ellipsis manually where neededonChange → individual onPress handlers on each Pagination.LinkPagination.Summary for showing result counts, custom icons via PreviousIcon/NextIcon childrenusePagination → build your own pagination logicvariant, color, radius, isCompact, showShadow → use Tailwind CSSclassName on individual compound components