# Pagination
**Category**: react
**URL**: https://heroui.com/en/docs/react/components/pagination
**Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/en/react/components/(navigation)/pagination.mdx
> Page navigation with composable page links, previous/next buttons, and ellipsis indicators
***
## Usage
```tsx
import { Pagination } from '@heroui/react';
```
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationBasic() {
const [page, setPage] = useState(1);
const totalPages = 3;
return (
setPage((p) => p - 1)}>
Previous
{Array.from({length: totalPages}, (_, i) => i + 1).map((p) => (
setPage(p)}>
{p}
))}
setPage((p) => p + 1)}>
Next
);
}
```
## Anatomy
```tsx
import { Pagination } from '@heroui/react';
export default () => (
Showing 1-10 of 100 results
Previous
1
10
Next
);
```
## Examples
### Sizes
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
function SizePagination({size}: {size: "sm" | "md" | "lg"}) {
const [page, setPage] = useState(1);
const totalPages = 3;
return (
{size}
setPage((p) => p - 1)}>
Previous
{Array.from({length: totalPages}, (_, i) => i + 1).map((p) => (
setPage(p)}>
{p}
))}
setPage((p) => p + 1)}>
Next
);
}
export function PaginationSizes() {
return (
{(["sm", "md", "lg"] as const).map((size) => (
))}
);
}
```
### Disabled
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationDisabled() {
const [page, setPage] = useState(1);
const totalPages = 3;
return (
setPage((p) => p - 1)}>
Previous
{Array.from({length: totalPages}, (_, i) => i + 1).map((p) => (
setPage(p)}>
{p}
))}
setPage((p) => p + 1)}>
Next
);
}
```
### Simple (Previous / Next)
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationSimplePrevNext() {
const [page, setPage] = useState(1);
const totalPages = 10;
const itemsPerPage = 5;
const totalItems = 50;
const startItem = (page - 1) * itemsPerPage + 1;
const endItem = Math.min(page * itemsPerPage, totalItems);
return (
{startItem} to {endItem} of {totalItems} invoices
setPage((p) => p - 1)}>
Prev
setPage((p) => p + 1)}>
Next
);
}
```
### Controlled
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationControlled() {
const [page, setPage] = useState(1);
const totalPages = 12;
const itemsPerPage = 10;
const totalItems = 120;
const getPageNumbers = () => {
const pages: (number | "ellipsis")[] = [];
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
pages.push(1);
if (page > 3) {
pages.push("ellipsis");
}
const start = Math.max(2, page - 1);
const end = Math.min(totalPages - 1, page + 1);
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (page < totalPages - 2) {
pages.push("ellipsis");
}
pages.push(totalPages);
}
return pages;
};
const startItem = (page - 1) * itemsPerPage + 1;
const endItem = Math.min(page * itemsPerPage, totalItems);
return (
Showing {startItem}-{endItem} of {totalItems} results
setPage((p) => p - 1)}>
Previous
{getPageNumbers().map((p, i) =>
p === "ellipsis" ? (
) : (
setPage(p)}>
{p}
),
)}
setPage((p) => p + 1)}>
Next
);
}
```
### With Ellipsis
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationWithEllipsis() {
const [page, setPage] = useState(1);
const totalPages = 12;
const getPageNumbers = () => {
const pages: (number | "ellipsis")[] = [];
pages.push(1);
if (page > 3) {
pages.push("ellipsis");
}
const start = Math.max(2, page - 1);
const end = Math.min(totalPages - 1, page + 1);
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (page < totalPages - 2) {
pages.push("ellipsis");
}
pages.push(totalPages);
return pages;
};
return (
setPage((p) => p - 1)}>
Previous
{getPageNumbers().map((p, i) =>
p === "ellipsis" ? (
) : (
setPage(p)}>
{p}
),
)}
setPage((p) => p + 1)}>
Next
);
}
```
### With Summary
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
export function PaginationWithSummary() {
const [page, setPage] = useState(1);
const totalPages = 12;
const itemsPerPage = 10;
const totalItems = 120;
const getPageNumbers = () => {
const pages: (number | "ellipsis")[] = [];
pages.push(1);
if (page > 3) {
pages.push("ellipsis");
}
const start = Math.max(2, page - 1);
const end = Math.min(totalPages - 1, page + 1);
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (page < totalPages - 2) {
pages.push("ellipsis");
}
pages.push(totalPages);
return pages;
};
const startItem = (page - 1) * itemsPerPage + 1;
const endItem = Math.min(page * itemsPerPage, totalItems);
return (
Showing {startItem}-{endItem} of {totalItems} results
setPage((p) => p - 1)}>
Previous
{getPageNumbers().map((p, i) =>
p === "ellipsis" ? (
) : (
setPage(p)}>
{p}
),
)}
setPage((p) => p + 1)}>
Next
);
}
```
### Custom Icons
You can replace the default chevron icons by passing custom children to `PreviousIcon` and `NextIcon`.
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {Icon} from "@iconify/react";
import {useState} from "react";
export function PaginationCustomIcons() {
const [page, setPage] = useState(1);
const totalPages = 3;
return (
setPage((p) => p - 1)}>
Back
{Array.from({length: totalPages}, (_, i) => i + 1).map((p) => (
setPage(p)}>
{p}
))}
setPage((p) => p + 1)}>
Forward
);
}
```
## Customization
### Tailwind CSS
```tsx
"use client";
import {Pagination} from "@heroui/react";
import {useState} from "react";
const linkClass = "text-muted hover:bg-surface hover:text-foreground";
const activeClass = "bg-accent text-accent-foreground hover:bg-accent-hover";
export function CustomStyles() {
const [page, setPage] = useState(2);
return (
setPage((p) => p - 1)}
>
{[1, 2, 3].map((p) => (
setPage(p)}
>
{p}
))}
setPage((p) => p + 1)}
>
);
}
```
### Global CSS
To customize the Pagination component classes, you can use the `@layer components` directive.
[Learn more](https://tailwindcss.com/docs/adding-custom-styles#adding-component-classes).
```css
@layer components {
.pagination {
@apply gap-8;
}
.pagination__link {
@apply rounded-md;
}
.pagination__summary {
@apply text-xs font-semibold;
}
}
```
## Styling Reference
HeroUI follows the [BEM](https://getbem.com/) methodology to ensure component variants and states are reusable and easy to customize.
### CSS Classes
The Pagination component uses these CSS classes ([View source styles](https://github.com/heroui-inc/heroui/blob/v3/packages/styles/components/pagination.css)):
#### Base & Layout Classes [!toc]
- `.pagination` - Root navigation container with flex layout
- `.pagination__summary` - Left-side info text container
- `.pagination__content` - Container for pagination items
- `.pagination__item` - Individual item wrapper
- `.pagination__link` - Page number button (ghost button style)
- `.pagination__link--nav` - Navigation button modifier (Previous/Next)
- `.pagination__ellipsis` - Ellipsis indicator
#### Size Classes [!toc]
- `.pagination--sm` - Small size variant
- `.pagination--md` - Medium size variant (default)
- `.pagination--lg` - Large size variant
### Interactive States
The component supports both CSS pseudo-classes and data attributes for flexibility:
- **Active page**: `[data-active="true"]` or `[aria-current="page"]`
- **Hover**: `:hover` or `[data-hovered="true"]`
- **Focus**: `:focus-visible` or `[data-focus-visible="true"]`
- **Disabled**: `:disabled` or `[aria-disabled="true"]`
- **Pressed**: `:active` or `[data-pressed="true"]`
## API Reference
### Pagination
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Size of the pagination items |
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | - | Pagination parts (Summary, Content) |
### Pagination.Summary
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | - | Summary content (e.g., "Showing 1-10 of 120") |
### Pagination.Content
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | - | Pagination items |
### Pagination.Item
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | - | Item content (Link, Previous, Next, or Ellipsis) |
### Pagination.Link
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `isActive` | `boolean` | `false` | Whether this is the current page |
| `isDisabled` | `boolean` | `false` | Whether the link is disabled |
| `onPress` | `(e: PressEvent) => void` | - | Press handler (from React Aria) |
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | - | Page number content |
### Pagination.Previous / Pagination.Next
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `isDisabled` | `boolean` | `false` | Whether the button is disabled |
| `onPress` | `(e: PressEvent) => void` | - | Press handler (from React Aria) |
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | - | Button content (compose with PreviousIcon/NextIcon) |
### Pagination.PreviousIcon / Pagination.NextIcon
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `className` | `string` | - | Additional CSS classes |
| `children` | `ReactNode` | Default chevron SVG | Custom icon to replace the default chevron |
### Pagination.Ellipsis
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `className` | `string` | - | Additional CSS classes |
## Note
Pagination buttons use `onPress` instead of `onClick`. The `onPress` handler from React Aria normalizes press behavior across pointer types and provides accessibility improvements out of the box.
## Accessibility
The Pagination component is built on [React Aria's Button](https://react-spectrum.adobe.com/react-aria/Button.html) primitive for all interactive elements, providing:
- Semantic `