# Pagination

Navigation between pages of results.

Source: [pagination.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/pagination.tsx)

```tsx
import * as React from "react";

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

const total = 12;

function pageList(current: number) {
  const pages = [...new Set([1, current - 1, current, current + 1, total])]
    .filter((page) => page >= 1 && page <= total)
    .sort((a, b) => a - b);
  const items: (number | "ellipsis")[] = [];
  let previous = 0;
  for (const page of pages) {
    if (page - previous > 1) items.push("ellipsis");
    items.push(page);
    previous = page;
  }
  return items;
}

export default function PaginationInteractive() {
  const [page, setPage] = React.useState(5);
  const go = (next: number) => (event: React.MouseEvent) => {
    event.preventDefault();
    setPage(Math.min(total, Math.max(1, next)));
  };

  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious href="#" onClick={go(page - 1)} disabled={page === 1} />
        </PaginationItem>
        {pageList(page).map((item, index) =>
          item === "ellipsis" ? (
            <PaginationItem key={`ellipsis-${index}`}>
              <PaginationEllipsis />
            </PaginationItem>
          ) : (
            <PaginationItem key={item}>
              <PaginationLink href="#" isActive={item === page} onClick={go(item)}>
                {item}
              </PaginationLink>
            </PaginationItem>
          ),
        )}
        <PaginationItem>
          <PaginationNext href="#" onClick={go(page + 1)} disabled={page === total} />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/pagination
```

## Usage

```tsx
import {
  Pagination,
  PaginationContent,
  PaginationEllipsis,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination";

export function InvoicePagination() {
  return (
    <Pagination>
      <PaginationContent>
        <PaginationItem>
          <PaginationPrevious href="?page=1" />
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="?page=1">1</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="?page=2" isActive>
            2
          </PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationEllipsis />
        </PaginationItem>
        <PaginationItem>
          <PaginationLink href="?page=12">12</PaginationLink>
        </PaginationItem>
        <PaginationItem>
          <PaginationNext href="?page=3" />
        </PaginationItem>
      </PaginationContent>
    </Pagination>
  );
}
```

Mark the current page with `isActive`. On the first or last page, set `disabled` on
`PaginationPrevious` or `PaginationNext`.

## Composition

- `Pagination`
  - `PaginationContent`
    - `PaginationItem`
      - `PaginationPrevious`
      - `PaginationLink`
      - `PaginationEllipsis`
      - `PaginationNext`

## Examples

### Compact

Leave out the page numbers when you only need previous and next. `text` changes their labels.

```tsx
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination";
import { preventNavigation } from "@/examples/data";

export default function PaginationCompact() {
  return (
    <div className="flex w-full max-w-lg flex-wrap items-center justify-between gap-3">
      <span className="text-sm text-muted-foreground tabular-nums">
        Showing 41–50 of 118 invoices
      </span>
      <Pagination className="mx-0 w-auto">
        <PaginationContent>
          <PaginationItem>
            <PaginationPrevious href="#" onClick={preventNavigation} text="Prev" />
          </PaginationItem>
          <PaginationItem>
            <PaginationNext href="#" onClick={preventNavigation} />
          </PaginationItem>
        </PaginationContent>
      </Pagination>
    </div>
  );
}
```

## Props

| Part | Extends |
| --- | --- |
| `Pagination` | `<nav>` |
| `PaginationContent` | `<ul>` |
| `PaginationItem` | `<li>` |
| `PaginationLink` | `<a>` |
| `PaginationPrevious` | `PaginationLink` |
| `PaginationNext` | `PaginationLink` |
| `PaginationEllipsis` | `<span>` |

### PaginationLink

| Prop        | Type                                                                                 | Description                                                       |
| ----------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| `isActive?` | `boolean`                                                                            |                                                                   |
| `disabled?` | `boolean`                                                                            | Dims the link and stops it navigating, for the ends of the range. |
| `size?`     | `"default" \| "icon" \| "icon-lg" \| "icon-sm" \| "icon-xs" \| "lg" \| "sm" \| "xs"` | Default: `"icon"`                                                 |

### PaginationPrevious

| Prop        | Type                                                                                 | Description                                                       |
| ----------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| `isActive?` | `boolean`                                                                            |                                                                   |
| `disabled?` | `boolean`                                                                            | Dims the link and stops it navigating, for the ends of the range. |
| `size?`     | `"default" \| "icon" \| "icon-lg" \| "icon-sm" \| "icon-xs" \| "lg" \| "sm" \| "xs"` | Default: `"default"`                                              |
| `text?`     | `string`                                                                             | Default: `"Previous"`                                             |

### PaginationNext

| Prop        | Type                                                                                 | Description                                                       |
| ----------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------- |
| `isActive?` | `boolean`                                                                            |                                                                   |
| `disabled?` | `boolean`                                                                            | Dims the link and stops it navigating, for the ends of the range. |
| `size?`     | `"default" \| "icon" \| "icon-lg" \| "icon-sm" \| "icon-xs" \| "lg" \| "sm" \| "xs"` | Default: `"default"`                                              |
| `text?`     | `string`                                                                             | Default: `"Next"`                                                 |
