# Pagination
> Pagination allows you to divide large amounts of content into smaller chunks across multiple pages.

## Import

```js
import { Pagination } from '@gemini-suite/vera-react';

// Optional hook that computes range of page numbers
import { usePagination } from '@gemini-suite/vera-react';
```

Pagination is a compound component that consists of multiple parts to help you create different kinds of pagination.

- `Pagination`: The outer pagination container with the accessible `role=navigation`.
- `Pagination.Arrow`: Left and right arrow controls with optional text labels.
- `Pagination.Numbers`: A wrapper for the list of page numbers.
- `Pagination.Number`: Page number controls.
- `Pagination.Ellipsis`: Indicates there are remaining pages.
- `Pagination.Label`: Indicates the current page in view (e.g., "Page 2", "1–10 of 50 results").

## Examples

### Minimal

At minimum, the **Pagination** should display arrows to navigate to the previous and next set of items in the paged dataset. However whenever possible, show the current page number too, so that users know where they are in a dataset.

<Callout variant="tip">

Hint when users are at the first or the last page by disabling the
corresponding `Pagination.Arrow`.

</Callout>

```jsx
() => {
  const [currentPage, setCurrentPage] = React.useState(1);
  const pageCount = 5;

  const handleForwardClick = () => {
    setCurrentPage(page => Math.min(page + 1, pageCount));
  };

  const handleBackClick = () => {
    setCurrentPage(page => Math.max(page - 1, 1));
  };

  return (
    <Pagination.Root
      as={Flex}
      wrap="wrap"
      label="Minimal pagination navigation"
    >
      <Pagination.Arrow
        label="Go to previous page"
        direction="back"
        onClick={handleBackClick}
        isDisabled={currentPage === 1}
      />
      <Pagination.Label color="foregroundNeutral">
        Page {currentPage}
      </Pagination.Label>
      <Pagination.Arrow
        label="Go to next page"
        direction="forward"
        onClick={handleForwardClick}
        isDisabled={currentPage === pageCount}
      />
    </Pagination.Root>
  );
};
```

### Pagination with custom labels

You may change the text labels shown to the user to provide users more information about what kind of data is in view and in what direction the pages are moving.

```jsx
<Pagination.Root as={Flex} label="Custom label pagination navigation">
  <Pagination.Arrow visibleLabel="Previous" direction="back" />
  <Pagination.Label className="is-visibleMedium" color="foregroundNeutral">
    October 2022
  </Pagination.Label>
  <Pagination.Arrow visibleLabel="Next" direction="forward" />
</Pagination.Root>
```

### Number pagination

**Pagination** makes it easy to display a list of page numbers for your users, so that they may easily navigate larger datasets.

<Callout variant="tip">

Pagination is commonly paired with tables, see [Table](/components/tables/table#pagination) component.

</Callout>

```jsx
<Pagination.Root
  as={Flex}
  gap="spacingS"
  cross="start"
  label="Number pagination navigation"
>
  <Pagination.Arrow label="Go to previous page" direction="back" />
  <Pagination.Numbers>
    <Pagination.Number label="Go to page 1">1</Pagination.Number>
    <Pagination.Number label="Go to page 2">2</Pagination.Number>
    <Pagination.Number label="Go to page 3" isCurrent>
      3
    </Pagination.Number>
    <Pagination.Number label="Go to page 4">4</Pagination.Number>
    <Pagination.Number label="Go to page 5">5</Pagination.Number>
  </Pagination.Numbers>
  <Pagination.Arrow label="Go to next page" direction="forward" />
</Pagination.Root>
```

### Number pagination with label

Use `Pagination.Label` for contextual information, like the current range of items.

<Callout variant="tip">

To keep the design simple on mobile, only the current range/page, next and
previous arrows can be displayed, by adding `is-visibleLarge` class to
`Pagination.Numbers`.

</Callout>

```jsx
<Pagination.Root
  as={Flex}
  main="space-between"
  wrap="wrap"
  label="Number pagination navigation with label"
>
  <Pagination.Label>Showing 1–10 of 49 results</Pagination.Label>
  <Flex gap="spacingS">
    <Pagination.Arrow isDisabled label="Go to previous page" direction="back" />
    <Pagination.Numbers className="is-visibleLarge">
      <Pagination.Number label="Go to page 1" isCurrent>
        1
      </Pagination.Number>
      <Pagination.Number label="Go to page 2">2</Pagination.Number>
      <Pagination.Number label="Go to page 3">3</Pagination.Number>
      <Pagination.Number label="Go to page 4">4</Pagination.Number>
      <Pagination.Number label="Go to page 5">5</Pagination.Number>
    </Pagination.Numbers>
    <Pagination.Arrow label="Go to next page" direction="forward" />
  </Flex>
</Pagination.Root>
```

### Sizes

Use `size` prop to control the size of the `Pagination`. `medium` and `small` sizes are available, with the `medium` size used by default.

```jsx
<Flex flow="column" gap="spacingL">
  <Flex flow="column">
    <Pagination.Root
      as={Flex}
      wrap="wrap"
      size="small"
      label="Small minimal pagination navigation"
    >
      <Pagination.Arrow
        label="Go to previous page"
        direction="back"
        isDisabled
      />
      <Pagination.Label color="foregroundNeutral">{'Page 1'}</Pagination.Label>
      <Pagination.Arrow label="Go to next page" direction="forward" />
    </Pagination.Root>
    <Pagination.Root
      as={Flex}
      wrap="wrap"
      label="Medium minimal pagination navigation"
    >
      <Pagination.Arrow
        label="Go to previous page"
        direction="back"
        isDisabled
      />
      <Pagination.Label color="foregroundNeutral">{'Page 1'}</Pagination.Label>
      <Pagination.Arrow label="Go to next page" direction="forward" />
    </Pagination.Root>
  </Flex>
  <Flex flow="column">
    <Pagination.Root
      as={Flex}
      gap="spacingS"
      size="small"
      label="Small number pagination navigation"
    >
      <Pagination.Arrow label="Go to previous page" direction="back" />
      <Pagination.Numbers>
        <Pagination.Number label="Go to page 1">1</Pagination.Number>
        <Pagination.Number label="Go to page 2">2</Pagination.Number>
        <Pagination.Number label="Go to page 3" isCurrent>
          3
        </Pagination.Number>
        <Pagination.Number label="Go to page 4">4</Pagination.Number>
        <Pagination.Number label="Go to page 5">5</Pagination.Number>
        <Pagination.Ellipsis label="Collapsed pages" />
        <Pagination.Number label="Go to page 15">15</Pagination.Number>
      </Pagination.Numbers>
      <Pagination.Arrow label="Go to next page" direction="forward" />
    </Pagination.Root>
    <Pagination.Root
      as={Flex}
      gap="spacingS"
      label="Medium number pagination navigation"
    >
      <Pagination.Arrow label="Go to previous page" direction="back" />
      <Pagination.Numbers>
        <Pagination.Number label="Go to page 1">1</Pagination.Number>
        <Pagination.Number label="Go to page 2">2</Pagination.Number>
        <Pagination.Number label="Go to page 3" isCurrent>
          3
        </Pagination.Number>
        <Pagination.Number label="Go to page 4">4</Pagination.Number>
        <Pagination.Number label="Go to page 5">5</Pagination.Number>
        <Pagination.Ellipsis label="Collapsed pages" />
        <Pagination.Number label="Go to page 15">15</Pagination.Number>
      </Pagination.Numbers>
      <Pagination.Arrow label="Go to next page" direction="forward" />
    </Pagination.Root>
  </Flex>
</Flex>
```

### With pagination hook

Vera exports `usePagination` hook that gives you a range of numbers to be rendered by the **Pagination**.
The hook accepts the following props:

- `pageCount`: represents the total number of pages.
- `currentPage`: represents the current active page (uses a 1-based index).
- `siblingCount` represents the min number of page numbers to be shown on each side of the current page (defaults to 1).

```js
const paginationRange = usePagination({
  currentPage: 1,
  pageCount: 10
});
```

When the total number of pages exceeds `siblingCount + 5`, the page numbers are truncated using an ellipsis.
Double truncation is used when there is more than one page number to be inserted between the extremes of sibling and the page limits.

<Callout variant="tip">

By default, `usePagination` will ensure that a maximum of seven pages (including the `Pagination.Ellipsis`) are shown.

</Callout>

```jsx
() => {
  const [currentPage, setCurrentPage] = React.useState(1);
  const pageCount = 15;

  const handleForwardClick = () => {
    setCurrentPage(page => Math.min(page + 1, pageCount));
  };

  const handleBackClick = () => {
    setCurrentPage(page => Math.max(page - 1, 1));
  };

  const handlePageClick = () => {
    setCurrentPage(parseInt(event.target.innerText));
  };

  const paginationRange = usePagination({
    currentPage,
    pageCount
  });

  return (
    <Pagination.Root
      as={Flex}
      wrap="wrap"
      gap="spacingS"
      label="Pagination navigation"
    >
      <Pagination.Arrow
        label="Go to previous page"
        direction="back"
        onClick={handleBackClick}
        isDisabled={currentPage === 1}
      />
      <Pagination.Numbers>
        {paginationRange.map((pageNumber, index) => {
          if (pageNumber === -1) {
            return (
              <Pagination.Ellipsis
                key={`dots-${index}`}
                label="Collapsed pages"
              />
            );
          }

          return (
            <Pagination.Number
              key={pageNumber}
              label={`Go to page ${pageNumber}`}
              isCurrent={pageNumber === currentPage}
              onClick={handlePageClick}
            >
              {pageNumber}
            </Pagination.Number>
          );
        })}
      </Pagination.Numbers>
      <Pagination.Arrow
        label="Go to next page"
        direction="forward"
        onClick={handleForwardClick}
        isDisabled={currentPage === pageCount}
      />
      <Pagination.Label>
        Page {currentPage} of {pageCount}
      </Pagination.Label>
    </Pagination.Root>
  );
};
```

### Pagination as anchor

**Pagination** navigates by the use of a button by default.
However, both the `Pagination.Arrow` and `Pagination.Number` can be set as anchors using the `as="a"` prop and including an `href` prop.

<Callout variant="tip">

Use anchors if the URL changes for each page.

</Callout>

```jsx
<Pagination.Root as={Flex} gap="spacingS" label="Anchor pagination navigation">
  <Pagination.Arrow
    as="a"
    href="#"
    label="Go to previous page"
    direction="back"
  />
  <Pagination.Numbers>
    <Pagination.Number as="a" href="#" label="Go to page 1">
      1
    </Pagination.Number>
    <Pagination.Number as="a" href="#" label="Go to page 2" isCurrent>
      2
    </Pagination.Number>
    <Pagination.Number as="a" href="#" label="Go to page 3">
      3
    </Pagination.Number>
  </Pagination.Numbers>
  <Pagination.Arrow
    as="a"
    href="#"
    label="Go to next page"
    direction="forward"
  />
</Pagination.Root>
```

---

## API Reference

### Pagination.Root

| Name    | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| ------- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`    | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `nav`    | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`   | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `size`  | `"small" \| "medium"`                                     | `medium` | The size of the pagination.                                                                                                                                                                                                                                                                  |          |
| `label` | `string`                                                  |          | The `aria-label` of the pagination navigation element to use for screen readers.                                                                                                                                                                                                             | Yes      |

### Pagination.Label

| Name    | Type                                                      | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ------- | --------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`    | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`   | `StitchesCss`                                             |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `color` | `ColorToken`                                              |         | The color of the label text. Subset of contrast-friendly foreground values from [color tokens](/tokens/colors) are available.                                                                                                                                                                |          |

### Pagination.Arrow

| Name           | Type                                                      | Default  | Description                                                                                                                                                                                                                                                                                  | Required |
| -------------- | --------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`           | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button` | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`          | `StitchesCss`                                             |          | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `direction`    | `"back" \| "forward"`                                     |          | The direction of the arrow control (either `back` or `forward`).                                                                                                                                                                                                                             | Yes      |
| `label`        | `string`                                                  |          | The `aria-label` to use for screen readers.                                                                                                                                                                                                                                                  |          |
| `visibleLabel` | `string`                                                  |          | Visible text of the arrow control.                                                                                                                                                                                                                                                           |          |
| `isDisabled`   | `boolean`                                                 | `false`  | When `true`, the control will be disabled, preventing the user from interacting with it.                                                                                                                                                                                                     |          |

### Pagination.Numbers

| Name  | Type          | Default | Description                                                                                                                                                                                                                                   | Required |
| ----- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css` | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |

### Pagination.Number

| Name         | Type                                                      | Default   | Description                                                                                                                                                                                                                                                                                  | Required |
| ------------ | --------------------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`         | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button`  | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`        | `StitchesCss`                                             |           | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                |          |
| `label`      | `string`                                                  |           | The `aria-label` to use for screen readers.                                                                                                                                                                                                                                                  | Yes      |
| `variant`    | `"ghost" \| "outline"`                                    | `"ghost"` | Visual variant of the number control.                                                                                                                                                                                                                                                        |          |
| `isCurrent`  | `boolean`                                                 | `false`   | When `true`, represents the currently selected page. `aria-current` prop is passed to the control element.                                                                                                                                                                                   |          |
| `isDisabled` | `boolean`                                                 | `false`   | When `true`, the control will be disabled, preventing the user from interacting with it.                                                                                                                                                                                                     |          |

### Pagination.Ellipsis

| Name    | Type          | Default | Description                                                                                                                                                                                                                                   | Required |
| ------- | ------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `css`   | `StitchesCss` |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants. |          |
| `label` | `string`      |         | The `aria-label` to use for screen readers.                                                                                                                                                                                                   | Yes      |

### usePagination

| Name           | Type     | Default | Description                                                              | Required |
| -------------- | -------- | ------- | ------------------------------------------------------------------------ | -------- |
| `currentPage`  | `number` |         | The currently selected page number.                                      | Yes      |
| `pageCount`    | `number` |         | The total number of pages.                                               | Yes      |
| `siblingCount` | `number` |         | Controls the number of pages displayed on each side of the current page. |          |
