> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Pagination

> Adds controls for navigating search result pages.

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">React</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="m6 9 6 6 6-6" />
      </svg>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/pagination/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/api-reference/widgets/pagination/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/pagination/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
    </ul>
  </div>
</div>

<Note>
  This is the **React InstantSearch v7** documentation.
  If you're upgrading from v6, see the [upgrade guide](/doc/guides/building-search-ui/upgrade-guides/react/#migrate-from-react-instantsearch-v6-to-react-instantsearch-v7).
  If you were using React InstantSearch Hooks,
  this v7 documentation applies—just check for [necessary changes](/doc/guides/building-search-ui/upgrade-guides/react/#migrate-from-react-instantsearch-hooks-to-react-instantsearch-v7).
  To continue using v6, you can find the [archived documentation](https://algolia.com/old-docs/deprecated/instantsearch/react/v6/api-reference/instantsearch/).
</Note>

```tsx Signature theme={"system"}
<Pagination
  // Optional props
  totalPages={number}
  padding={number}
  showFirst={boolean}
  showPrevious={boolean}
  showNext={boolean}
  showLast={boolean}
  classNames={object}
  translations={object}
  ...props={ComponentProps<'div'>}
/>
```

## Import

```js JavaScript icon=code theme={"system"}
import { Pagination } from "react-instantsearch";
```

<Card title="See this widget in action" icon="monitor-play" href="https://instantsearchjs.netlify.app/stories/js/?path=/story/refinements-Pagination--default" horizontal>
  Preview this widget and its behavior.
</Card>

## About this widget

`<Pagination>` is a widget that displays a pagination to browse pages.

<Info>
  Pagination is limited to 1,000 hits per page.
  For more information, see [Pagination limitations](/doc/guides/building-search-ui/ui-and-ux-patterns/pagination/react#pagination-limitations).
</Info>

<Tip>You can also create your own UI with [`usePagination`](#hook).</Tip>

## Examples

```jsx JavaScript icon=code theme={"system"}
import React from "react";
import { liteClient as algoliasearch } from "algoliasearch/lite";
import { InstantSearch, Pagination } from "react-instantsearch";

const searchClient = algoliasearch("YourApplicationID", "YourSearchOnlyAPIKey");

function App() {
  return (
    <InstantSearch indexName="instant_search" searchClient={searchClient}>
      <Pagination />
    </InstantSearch>
  );
}
```

## Props

<ParamField body="totalPages" type="number">
  The maximum number of pages to browse.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination totalPages={2} />;
  ```
</ParamField>

<ParamField body="padding" type="number" default={3}>
  The number of pages to display on each side of the current page.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination padding={2} />;
  ```
</ParamField>

<ParamField body="showFirst" default={true}>
  Whether to display the first page link.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination showFirst={false} />;
  ```
</ParamField>

<ParamField body="showPrevious" default={true}>
  Whether to display the previous page link.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination showPrevious={false} />;
  ```
</ParamField>

<ParamField body="showNext" default={true}>
  Whether to display the next page link.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination showNext={false} />;
  ```
</ParamField>

<ParamField body="showLast" default={true}>
  Whether to display the last page link.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination showLast={false} />;
  ```
</ParamField>

<ParamField body="classNames" type="Partial<PaginationClassNames>">
  The [CSS classes you can override](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/react#style-your-widgets) and pass to the widget's elements.
  It's useful to style widgets with class-based CSS frameworks like [Bootstrap](https://getbootstrap.com) or [Tailwind CSS](https://tailwindcss.com).

  * `root`. The root element of the widget.
  * `noRefinementRoot`. The root element when there are no refinements.
  * `list`. The list element.
  * `item`. Each item element.
  * `firstPageItem`. The first page element.
  * `previousPageItem`. The previous page element.
  * `pageItem`. Each page element.
  * `selectedItem`. The selected page element.
  * `disabledItem`. Each disabled page element.
  * `nextPageItem`. The next page element.
  * `lastPageItem`. The last page element.
  * `link`. The link of each item.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination
    classNames={{
      root: "MyCustomPagination",
      list: "MyCustomPaginationList MyCustomPaginationList--subclass",
    }}
  />;
  ```
</ParamField>

<ParamField body="translations" type="Partial<PaginationTranslations>">
  A mapping of keys to translation values.

  * `firstPageItemText`. The text for the first page item.
  * `previousPageItemText`. The text for the previous page item.
  * `nextPageItemText`. The text for the next page item.
  * `lastPageItemText`. The text for the last page item.
  * `pageItemText`. The text for the current page item.
  * `firstPageItemAriaLabel`. The label for the first page item (for screen readers).
  * `previousPageItemAriaLabel`. The label for the previous page item (for screen readers).
  * `nextPageItemAriaLabel`. The label for the next page item (for screen readers).
  * `lastPageItemAriaLabel`. The label for the last page item (for screen readers).
  * `pageItemAriaLabel`. The label for the current page item (for screen readers).

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination
    translations={{
      firstPageItemText: "First page",
      previousPageItemText: "Previous page",
      nextPageItemText: "Next page",
      lastPageItemText: "Last page",
      pageItemText: ({ currentPage, nbPages }) =>
        `Page ${currentPage}/${nbPages}`,
      firstPageItemAriaLabel: "Go to first page",
      previousPageItemAriaLabel: "Go to previous page",
      nextPageItemAriaLabel: "Go to next page",
      lastPageItemAriaLabel: "Go to last page",
      pageItemAriaLabel: ({ currentPage, nbPages }) =>
        `Go to page ${currentPage} of ${nbPages}`,
    }}
  />;
  ```
</ParamField>

<ParamField body="...props" type="React.ComponentProps<'div'>">
  Any `<div>` prop to forward to the root element of the widget.

  ```jsx JavaScript icon=code theme={"system"}
  <Pagination className="MyCustomPagination" title="My custom title" />;
  ```
</ParamField>

## Hook

React InstantSearch let you create your own UI for the `<Pagination>` widget with `usePagination`.
Hooks provide APIs to access the widget state and interact with InstantSearch.

The `usePagination` Hook accepts [parameters](#parameters) and returns [APIs](#hook).
It must be used inside the [`<InstantSearch>`](/doc/api-reference/widgets/instantsearch/react) component.

### Usage

First, create your React component:

```jsx JavaScript icon=code theme={"system"}
import { usePagination } from "react-instantsearch";

function CustomPagination(props) {
  const {
    pages,
    currentRefinement,
    nbHits,
    nbPages,
    isFirstPage,
    isLastPage,
    canRefine,
    refine,
    createURL,
  } = usePagination(props);

  return <>{/*Your JSX*/}</>;
}
```

Then, render the widget:

```jsx JavaScript icon=code theme={"system"}
<CustomPagination {...props} />
```

### Parameters

Hooks accept parameters. You can either pass them manually or forward props from a custom component.

<Note>
  When passing functions to Hooks, ensure stable references to prevent unnecessary re-renders.
  Use [`useCallback()`](https://reactjs.org/docs/hooks-reference.html#usecallback) for memoization.
  Arrays and objects are automatically memoized.
</Note>

<ParamField body="totalPages" type="number">
  The maximum number of pages to browse.

  ```jsx JavaScript icon=code theme={"system"}
  const paginationApi = usePagination({
    totalPages: 2,
  });
  ```
</ParamField>

<ParamField body="padding" type="number" default={3}>
  The number of pages to display on each side of the current page.

  ```jsx JavaScript icon=code theme={"system"}
  const paginationApi = usePagination({
    padding: 2,
  });
  ```
</ParamField>

### APIs

Hooks return APIs, such as state and functions.
You can use them to build your UI and interact with React InstantSearch.

<ParamField body="pages" type="number[]">
  The list of pages based on the current page and [`padding`](/doc/api-reference/widgets/pagination/react#param-padding).

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { pages, refine } = usePagination(props);

    return (
      <ul>
        {pages.map((page) => (
          <li key={page}>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page + 1}
            </a>
          </li>
        ))}
      </ul>
    );
  }
  ```
</ParamField>

<ParamField body="currentRefinement" type="number">
  The current page number.

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { currentRefinement, pages, refine } = usePagination(props);

    return (
      <ul>
        {pages.map((page) => (
          <li key={page}>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page === currentRefinement ? <strong>{page}</strong> : page}
            </a>
          </li>
        ))}
      </ul>
    );
  }
  ```
</ParamField>

<ParamField body="nbHits" type="number">
  The number of hits (can be approximate).

  ```jsx JavaScript icon=code theme={"system"}
  function PageIndicator(props) {
    const { currentRefinement, nbPages, nbHits } = usePagination(props);

    return (
      <p>
        {currentRefinement + 1} of {nbPages} page(s) for {nbHits} hit(s)
      </p>
    );
  }
  ```
</ParamField>

<ParamField body="nbPages" type="number">
  The number of pages for the total result set.

  ```jsx JavaScript icon=code theme={"system"}
  function PageIndicator(props) {
    const { currentRefinement, nbPages, nbHits } = usePagination(props);

    return (
      <p>
        {currentRefinement + 1} of {nbPages} page(s) for {nbHits} hit(s)
      </p>
    );
  }
  ```
</ParamField>

<ParamField body="isFirstPage" type="boolean">
  Whether the current page is the first page.

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { isFirstPage, pages, refine } = usePagination(props);

    return (
      <ul>
        {isFirstPage ? null : (
          <li>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(0);
              }}
            >
              First Page
            </a>
          </li>
        )}
        {pages.map((page) => (
          <li key={page}>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page + 1}
            </a>
          </li>
        ))}
      </ul>
    );
  }
  ```
</ParamField>

<ParamField body="isLastPage" type="boolean">
  Whether the current page is the last page.

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { isLastPage, nbPages, pages, refine } = usePagination(props);

    return (
      <ul>
        {pages.map((page) => (
          <li key={page}>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page + 1}
            </a>
          </li>
        ))}
        {isLastPage ? null : (
          <li>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(nbPages - 1);
              }}
            >
              Last Page
            </a>
          </li>
        )}
      </ul>
    );
  }
  ```
</ParamField>

<ParamField body="canRefine" type="boolean">
  Indicates if the pagination can be refined.

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { canRefine, pages, refine } = usePagination(props);

    if (!canRefine) {
      return null;
    }

    return (
      <ul>
        {pages.map((page) => (
          <li key={page}>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page + 1}
            </a>
          </li>
        ))}
      </ul>
    );
  }
  ```
</ParamField>

<ParamField body="refine" type="(page: number) => void">
  Sets the current page and triggers a search.

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { pages, refine } = usePagination(props);

    return (
      <ul>
        {pages.map((page) => (
          <li key={page}>
            <a
              href="#"
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page + 1}
            </a>
          </li>
        ))}
      </ul>
    );
  }
  ```
</ParamField>

<ParamField body="createURL" type="(page: number) => string">
  Generates a URL of the next search state.

  ```jsx JavaScript icon=code theme={"system"}
  function Pagination(props) {
    const { canRefine, pages, refine } = usePagination(props);

    return (
      <ul>
        {pages.map((page) => (
          <li key={page}>
            <a
              href={createURL(page)}
              onClick={(event) => {
                event.preventDefault();
                refine(page);
              }}
            >
              {page + 1}
            </a>
          </li>
        ))}
      </ul>
    );
  }
  ```
</ParamField>

### Example

<CodeGroup>
  ```jsx JavaScript theme={"system"}
  import React from "react";
  import { usePagination } from "react-instantsearch";

  function CustomPagination(props) {
    const {
      pages,
      currentRefinement,
      nbPages,
      isFirstPage,
      isLastPage,
      refine,
      createURL,
    } = usePagination(props);
    const firstPageIndex = 0;
    const previousPageIndex = currentRefinement - 1;
    const nextPageIndex = currentRefinement + 1;
    const lastPageIndex = nbPages - 1;

    return (
      <ul>
        <PaginationItem
          isDisabled={isFirstPage}
          href={createURL(firstPageIndex)}
          onClick={() => refine(firstPageIndex)}
        >
          First
        </PaginationItem>
        <PaginationItem
          isDisabled={isFirstPage}
          href={createURL(previousPageIndex)}
          onClick={() => refine(previousPageIndex)}
        >
          Previous
        </PaginationItem>
        {pages.map((page) => {
          const label = page + 1;

          return (
            <PaginationItem
              key={page}
              isDisabled={false}
              aria-label={`Page ${label}`}
              href={createURL(page)}
              onClick={() => refine(page)}
            >
              {label}
            </PaginationItem>
          );
        })}
        <PaginationItem
          isDisabled={isLastPage}
          href={createURL(nextPageIndex)}
          onClick={() => refine(nextPageIndex)}
        >
          Next
        </PaginationItem>
        <PaginationItem
          isDisabled={isLastPage}
          href={createURL(lastPageIndex)}
          onClick={() => refine(lastPageIndex)}
        >
          Last
        </PaginationItem>
      </ul>
    );
  }

  function PaginationItem({ isDisabled, href, onClick, ...props }) {
    if (isDisabled) {
      return (
        <li>
          <span {...props} />
        </li>
      );
    }

    return (
      <li>
        <a
          href={href}
          onClick={(event) => {
            if (isModifierClick(event)) {
              return;
            }

            event.preventDefault();

            onClick(event);
          }}
          {...props}
        />
      </li>
    );
  }

  function isModifierClick(event) {
    const isMiddleClick = event.button === 1;

    return Boolean(
      isMiddleClick ||
        event.altKey ||
        event.ctrlKey ||
        event.metaKey ||
        event.shiftKey,
    );
  }
  ```

  ```tsx TypeScript theme={"system"}
  import React from "react";
  import { usePagination, UsePaginationProps } from "react-instantsearch";

  function CustomPagination(props: UsePaginationProps) {
    const {
      pages,
      currentRefinement,
      nbPages,
      isFirstPage,
      isLastPage,
      refine,
      createURL,
    } = usePagination(props);
    const firstPageIndex = 0;
    const previousPageIndex = currentRefinement - 1;
    const nextPageIndex = currentRefinement + 1;
    const lastPageIndex = nbPages - 1;

    return (
      <ul>
        <PaginationItem
          isDisabled={isFirstPage}
          href={createURL(firstPageIndex)}
          onClick={() => refine(firstPageIndex)}
        >
          First
        </PaginationItem>
        <PaginationItem
          isDisabled={isFirstPage}
          href={createURL(previousPageIndex)}
          onClick={() => refine(previousPageIndex)}
        >
          Previous
        </PaginationItem>
        {pages.map((page) => {
          const label = page + 1;

          return (
            <PaginationItem
              key={page}
              isDisabled={false}
              aria-label={`Page ${label}`}
              href={createURL(page)}
              onClick={() => refine(page)}
            >
              {label}
            </PaginationItem>
          );
        })}
        <PaginationItem
          isDisabled={isLastPage}
          href={createURL(nextPageIndex)}
          onClick={() => refine(nextPageIndex)}
        >
          Next
        </PaginationItem>
        <PaginationItem
          isDisabled={isLastPage}
          href={createURL(lastPageIndex)}
          onClick={() => refine(lastPageIndex)}
        >
          Last
        </PaginationItem>
      </ul>
    );
  }

  type PaginationItemProps = Omit<React.ComponentProps<"a">, "onClick"> & {
    onClick: NonNullable<React.ComponentProps<"a">["onClick"]>;
    isDisabled: boolean;
  };

  function PaginationItem({
    isDisabled,
    href,
    onClick,
    ...props
  }: PaginationItemProps) {
    if (isDisabled) {
      return (
        <li>
          <span {...props} />
        </li>
      );
    }

    return (
      <li>
        <a
          href={href}
          onClick={(event) => {
            if (isModifierClick(event)) {
              return;
            }

            event.preventDefault();

            onClick(event);
          }}
          {...props}
        />
      </li>
    );
  }

  function isModifierClick(event: React.MouseEvent) {
    const isMiddleClick = event.button === 1;

    return Boolean(
      isMiddleClick ||
        event.altKey ||
        event.ctrlKey ||
        event.metaKey ||
        event.shiftKey
    );
  }
  ```
</CodeGroup>
