Back to Heroui

Pagination

apps/docs/content/docs/react/migration/(components)/pagination.mdx

3.0.412.1 KB
Original Source
<Callout type="info"> Refer to the [v3 Pagination documentation](/docs/react/components/pagination) for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2. </Callout>

Structure Changes

In v2, Pagination was a single component that handled all rendering internally via props:

tsx
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:

tsx
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>
  );
}

Key Changes

1. Component Structure

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

2. Page Generation

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.

3. Prop Changes

v2 Propv3 EquivalentNotes
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)
sizePagination sizeSame (sm, md, lg)
variant-Removed (use Tailwind CSS)
color-Removed (use Tailwind CSS)
radius-Removed (use Tailwind CSS)
isDisabledisDisabled on Pagination.Link, Pagination.Previous, Pagination.NextPer-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

4. Hook Changes

v2: usePagination hook available for custom implementations v3: No built-in hook — compose pagination items directly or build your own pagination logic

Migration Examples

Basic Pagination

<Tabs items={["v2", "v3"]}> <Tab value="v2"> ```tsx import { Pagination } from "@heroui/react";

<Pagination total={10} initialPage={1} />
```
</Tab> <Tab value="v3"> ```tsx import { useState } from "react"; import { Pagination } from "@heroui/react";
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>
```
</Tab> </Tabs>

With Previous / Next Controls

<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>
```
</Tab> </Tabs>

With Ellipsis

<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>
```
</Tab> </Tabs>

Simple Previous / Next Only

<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>
```
</Tab> </Tabs>

With Summary

<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>
```
</Tab> </Tabs>

Custom Icons

<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>
```
</Tab> </Tabs>

Styling Changes

v2: classNames Prop

tsx
<Pagination
  classNames={{
    base: "custom-base",
    wrapper: "custom-wrapper",
    prev: "custom-prev",
    next: "custom-next",
    item: "custom-item",
    cursor: "custom-cursor",
    ellipsis: "custom-ellipsis",
  }}
/>

v3: Direct className Props

tsx
<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>

Component Anatomy

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)

Summary

  1. Component Structure: Single auto-generating component → compound components with manual composition
  2. Page Generation: total/siblings/boundaries props → compose page items manually with your own pagination logic
  3. Active Page: page/initialPage props → isActive prop on individual Pagination.Link
  4. Navigation Controls: showControls prop → compose Pagination.Previous and Pagination.Next directly
  5. Ellipsis: Auto-generated → compose Pagination.Ellipsis manually where needed
  6. Events: Single onChange → individual onPress handlers on each Pagination.Link
  7. New Features: Pagination.Summary for showing result counts, custom icons via PreviousIcon/NextIcon children
  8. Hook Removed: usePagination → build your own pagination logic
  9. Styling Props Removed: variant, color, radius, isCompact, showShadow → use Tailwind CSS
  10. ClassNames Removed: Use className on individual compound components