# Pagination

Move between pages of a long list or table.

Paging through ten pages

[Complete TSX file](/examples/pagination/default.tsx)

```tsx
"use client";

import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/siteplane/components/pagination";
import { useState } from "react";

const totalPages = 10;

type PageItem = number | "start-ellipsis" | "end-ellipsis";

// Seven slots at every page, so the control keeps its width while it pages.
function getPageItems(page: number, total: number): PageItem[] {
  if (page <= 4) return [1, 2, 3, 4, 5, "end-ellipsis", total];
  if (page >= total - 3) {
    return [
      1,
      "start-ellipsis",
      total - 4,
      total - 3,
      total - 2,
      total - 1,
      total,
    ];
  }
  return [1, "start-ellipsis", page - 1, page, page + 1, "end-ellipsis", total];
}

export default function Example() {
  const [page, setPage] = useState(5);

  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious
            disabled={page === 1}
            onClick={() => setPage(page - 1)}
          />
        </PaginationItem>
        {getPageItems(page, totalPages).map((item) => (
          <PaginationItem key={item}>
            {typeof item === "number" ? (
              <PaginationLink
                active={item === page}
                onClick={() => setPage(item)}
              >
                {item}
              </PaginationLink>
            ) : (
              <PaginationEllipsis />
            )}
          </PaginationItem>
        ))}
        <PaginationItem>
          <PaginationNext
            disabled={page === totalPages}
            onClick={() => setPage(page + 1)}
          />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}
```

## Installation

Complete [one-time setup](/docs/installation/) first.

```bash
pnpm dlx shadcn@4.18.0 add @siteplane/pagination
```

With npm: `npx shadcn@4.18.0 add @siteplane/pagination`. [Registry JSON](/registry/pagination.json) lists source files and dependencies.

## Usage

```tsx
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
} from "@/siteplane/components/pagination";

<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationLink active>1</PaginationLink>
    </PaginationItem>
  </PaginationContent>
</Pagination>;
```

## Composition

```text
Pagination
└── PaginationContent
    └── PaginationItem
        └── PaginationPrevious / PaginationLink / PaginationNext / PaginationEllipsis
```

## Compact navigation

`variant="ghost"` hides the Previous and Next text and keeps icon buttons with their accessible names. Use it where space is tight, for example below a table.

Compact pagination

[Complete TSX file](/examples/pagination/ghost.tsx)

```tsx
"use client";

import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/siteplane/components/pagination";
import { useState } from "react";

const pages = [1, 2, 3, 4, 5];

export default function Example() {
  const [page, setPage] = useState(3);

  return (
    <Pagination variant="ghost">
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious
            disabled={page === 1}
            onClick={() => setPage(page - 1)}
          />
        </PaginationItem>
        {pages.map((number) => (
          <PaginationItem key={number}>
            <PaginationLink
              active={page === number}
              onClick={() => setPage(number)}
            >
              {number}
            </PaginationLink>
          </PaginationItem>
        ))}
        <PaginationItem>
          <PaginationNext
            disabled={page === pages.length}
            onClick={() => setPage(page + 1)}
          />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}
```

## API reference

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| Pagination.variant | default \| ghost | default | Directional navigation display. |
| Pagination.animate | boolean | true | Active indicator motion; reduced motion is respected. |
| Pagination.labels | Partial<PaginationLabels> | English | Replaces the words of the parts, each one on its own: navigation ("pagination", the landmark name), previous ("Previous"), previousPage ("Go to previous page"), next ("Next"), nextPage ("Go to next page") and morePages ("More pages"). Pass their translation when the application is in another language. |
| PaginationContent / PaginationItem | ul / li props | — | Content measures the active item; item supplies list semantics. |
| PaginationLink.active | boolean | false | Sets aria-current="page" and the active indicator. isActive is a deprecated alias. |
| PaginationLink.size | ButtonStandardProps["size"] | Icon size from provider | Explicit button size override. A page link is at least square, and a longer number widens it with 4 px on each side. |
| PaginationLink render / disabled / onClick | ButtonStandardProps | ghost button | Application owns navigation and disabled boundaries. |
| PaginationPrevious / PaginationNext | ButtonBaseProps & { active?: boolean } | size: provider / lg | Directional buttons with fixed icon and label from Pagination labels; default variant responds to viewport width. The chevrons mirror in a right-to-left page. |
| PaginationEllipsis | span props | — | Decorative gap, not a navigation action. |

Exported types: `PaginationProps`, `PaginationLinkProps`, `PaginationLabels`. These describe the props above.

[Read the installed source](/source/pagination).

## Usage notes

No page count, slicing, URL state, or data fetching is built in. Set those in the application. The examples keep the current page in state: `active` marks the current link, `onClick` changes the page, and `disabled` stops Previous and Next at the first and last page. They also decide which page numbers to show; the first example always renders seven slots, so the control keeps its width while it pages. Root accepts native nav props. Link and direction controls inherit the corresponding [Button API](/docs/components/button/#api-reference).

A page link keeps the square of its size for a short number. A longer one, such as 1,248, widens the link with 4 px on each side instead of filling the square edge to edge, and the active indicator follows its width. Format the numbers for the application's locale; the links show the text you pass.

`labels` replaces the words that Pagination renders, merged with the English defaults, for example `labels={{ previous: "Zurück", previousPage: "Zur vorherigen Seite", next: "Weiter", nextPage: "Zur nächsten Seite" }}`. An `aria-label` on PaginationPrevious or PaginationNext still replaces its accessible name. In a right-to-left page Previous sits on the right and Next on the left, and their chevrons point outward.
