Pro--% off in--d : --h : --m : --s
HeroUI

Pagination

Migration guide for Pagination from HeroUI v2 to v3

Refer to the v3 Pagination documentation for complete API reference, styling guide, and advanced examples. This guide only focuses on migrating from HeroUI v2.

Structure Changes

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

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

import { Pagination } from "@heroui/react";

<Pagination total={10} initialPage={1} />
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>

With Previous / Next Controls

<Pagination total={10} initialPage={1} showControls />
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>

With Ellipsis

<Pagination total={20} initialPage={1} siblings={1} boundaries={1} />
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>

Simple Previous / Next Only

{/* v2 didn't have a built-in simple prev/next pattern */}
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>

With Summary

{/* v2 didn't have a built-in summary slot */}
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 items */}
  </Pagination.Content>
</Pagination>

Custom Icons

{/* v2 required renderItem for custom icons */}
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>
    {/* Page links */}
    <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>

Styling Changes

v2: 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",
  }}
/>

v3: Direct 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>

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

On this page