Components

Pagination

Page navigation with numbered links, previous/next controls, and ellipsis for long page ranges.

Category: Navigation — Pattern: Pure React Composite

Preview

Loading preview...
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationPrevious,
  PaginationNext,
} from "@hareru/ui"

<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious href="/page/1">Previous</PaginationPrevious>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/1">1</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/2" isActive>2</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/3">3</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext href="/page/3">Next</PaginationNext>
    </PaginationItem>
  </PaginationContent>
</Pagination>

Import

import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationPrevious,
  PaginationNext,
  PaginationEllipsis,
} from "@hareru/ui"

Exports

NameTypeDescription
PaginationComponentRoot <nav> wrapper with aria-label="Pagination"
PaginationContentComponent<ul> list container for pagination items
PaginationItemComponent<li> wrapper for each pagination entry
PaginationLinkComponentPage number link; supports isActive, size variant, and asChild
PaginationPreviousComponentPrevious page link with disabled support
PaginationNextComponentNext page link with disabled support
PaginationEllipsisComponentEllipsis indicator for skipped page ranges
paginationLinkVariantsCVA functionVariant helper for link size classes

Key Props

PropTypeDefaultDescription
isActivebooleanfalseMarks the current page (aria-current="page")
size'sm' | 'md' | 'lg''md'Link size variant
asChildbooleanfalseRender as the child element for router integration

PaginationPrevious / PaginationNext

PropTypeDefaultDescription
disabledbooleanfalseDisables the control (aria-disabled, tabIndex=-1, pointer-events: none)
asChildbooleanfalseRender as the child element for router integration

Structure

  • PaginationContent [container] (expected)
    • PaginationItem [item] (expected) ×N
      • PaginationLink [trigger]
      • PaginationPrevious [trigger]
      • PaginationNext [trigger]
      • PaginationEllipsis [indicator]

(expected) = recommended in canonical composition, not runtime-required.

Accessibility

  • Roles: navigation
  • ARIA attributes: aria-label="Pagination", aria-current="page", aria-disabled, aria-label
  • Semantic elements: nav, ul, li
  • Keyboard:
    • Tab to navigate between page links
  • Notes: Uses nav landmark with aria-label. Active page marked with aria-current="page". Disabled controls use aria-disabled, tabIndex={-1}, and CSS pointer-events: none.

Usage

import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationPrevious,
  PaginationNext,
  PaginationEllipsis,
} from "@hareru/ui"

// Basic pagination
<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious href="/page/1">Previous</PaginationPrevious>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/1">1</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/2" isActive>2</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/3">3</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext href="/page/3">Next</PaginationNext>
    </PaginationItem>
  </PaginationContent>
</Pagination>

// With ellipsis and disabled controls
<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious disabled>Previous</PaginationPrevious>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/1" isActive>1</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/2">2</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/3">3</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationEllipsis />
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="/page/10">10</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext href="/page/2">Next</PaginationNext>
    </PaginationItem>
  </PaginationContent>
</Pagination>

// With Next.js Link (asChild)
import Link from "next/link"

<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious asChild>
        <Link href="/page/1">Previous</Link>
      </PaginationPrevious>
    </PaginationItem>
    <PaginationItem>
      <PaginationLink asChild isActive>
        <Link href="/page/2">2</Link>
      </PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext asChild>
        <Link href="/page/3">Next</Link>
      </PaginationNext>
    </PaginationItem>
  </PaginationContent>
</Pagination>

Notes

  • PaginationLink size variants (sm, md, lg) control the minimum width and height of the link element.
  • PaginationPrevious and PaginationNext accept a disabled prop that applies aria-disabled="true", tabIndex={-1}, and CSS pointer-events: none. When not using asChild, href is also removed. When using asChild, the parent calls e.preventDefault() via Slot handler merge to prevent navigation.
  • PaginationEllipsis renders and is aria-hidden — use it between page ranges to indicate skipped pages.
  • All link components support asChild for framework router integration (e.g. Next.js Link, React Router Link).

On this page