---
title: Pagination
description: >-
  The [Storefront API uses
  cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate
  through lists of data and the `<Pagination />` component makes it easy to
  paginate data from the Storefront API. It is important for pagination state to
  be maintained in the URL, so that the user can navigate to a product and
  return back to the same scrolled position in a list. It is also important that
  the list state is shareable via URL. The `<Pagination>` component provides a
  render prop with properties to load more elements into your list.
api_version: 2023-10
api_name: hydrogen
source_url:
  html: 'https://shopify.dev/docs/api/hydrogen/2023-10/components/pagination'
  md: 'https://shopify.dev/docs/api/hydrogen/2023-10/components/pagination.md'
---

# Pagination

The [Storefront API uses cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate through lists of data and the `<Pagination />` component makes it easy to paginate data from the Storefront API. It is important for pagination state to be maintained in the URL, so that the user can navigate to a product and return back to the same scrolled position in a list. It is also important that the list state is shareable via URL. The `<Pagination>` component provides a render prop with properties to load more elements into your list.

## Props

* **connection**

  **Connection\<NodesType>**

  **required**

  The response from `storefront.query` for a paginated request. Make sure the query is passed pagination variables and that the query has `pageInfo` with `hasPreviousPage`, `hasNextpage`, `startCursor`, and `endCursor` defined.

* **children**

  **PaginationRenderProp\<NodesType>**

  **required**

  A render prop that includes pagination data and helpers.

### Connection

```ts
{
      nodes: Array<NodesType>;
      pageInfo: PageInfo;
    } | {
      edges: Array<{
        node: NodesType;
      }>;
      pageInfo: PageInfo;
    }
```

### PaginationRenderProp

* props

  ```ts
  PaginationInfo<NodesType>
  ```

ReactNode

```ts
ReactNode
```

### PaginationInfo

* nodes

  The paginated array of nodes. You should map over and render this array.

  ```ts
  Array<NodesType>
  ```

* NextLink

  The \`\<NextLink>\` is a helper component that makes it easy to navigate to the next page of paginated data. Alternatively you can build your own \`\<Link>\` component: \`\<Link to={nextPageUrl} state={state} preventScrollReset />\`

  ```ts
  (props: Omit<RemixLinkProps, "to"> & { ref?: Ref<HTMLAnchorElement>; }) => ReactNode
  ```

* PreviousLink

  The \`\<PreviousLink>\` is a helper component that makes it easy to navigate to the previous page of paginated data. Alternatively you can build your own \`\<Link>\` component: \`\<Link to={previousPageUrl} state={state} preventScrollReset />\`

  ```ts
  (props: Omit<RemixLinkProps, "to"> & { ref?: Ref<HTMLAnchorElement>; }) => ReactNode
  ```

* previousPageUrl

  The URL to the previous page of paginated data. Use this prop to build your own \`\<Link>\` component.

  ```ts
  string
  ```

* nextPageUrl

  The URL to the next page of paginated data. Use this prop to build your own \`\<Link>\` component.

  ```ts
  string
  ```

* hasNextPage

  True if the cursor has next paginated data

  ```ts
  boolean
  ```

* hasPreviousPage

  True if the cursor has previous paginated data

  ```ts
  boolean
  ```

* isLoading

  True if we are in the process of fetching another page of data

  ```ts
  boolean
  ```

* state

  The \`state\` property is important to use when building your own \`\<Link>\` component if you want paginated data to continuously append to the page. This means that every time the user clicks "Next page", the next page of data will be apppended inline with the previous page. If you want the whole page to re-render with only the next page results, do not pass the \`state\` prop to the Remix \`\<Link>\` component.

  ```ts
  { nodes: NodesType[]; pageInfo: { endCursor: string; startCursor: string; hasPreviousPage: boolean; }; }
  ```

Examples

### Examples

* #### Example code

  ##### Description

  I am the default example

  ##### JavaScript

  ```jsx
  import {json} from '@shopify/remix-oxygen';
  import {Pagination, getPaginationVariables} from '@shopify/hydrogen';
  import {useLoaderData, Link} from '@remix-run/react';

  export async function loader({request, context: {storefront}}) {
    const variables = getPaginationVariables(request, {pageBy: 8});

    const data = await storefront.query(ALL_PRODUCTS_QUERY, {
      variables,
    });

    return json({products: data.products});
  }

  export default function List() {
    const {products} = useLoaderData();

    return (
      <Pagination connection={products}>
        {({nodes, PreviousLink, NextLink}) => (
          <>
            <PreviousLink>Previous</PreviousLink>
            <div>
              {nodes.map((product) => (
                <Link key={product.id} to={`/products/${product.handle}`}>
                  {product.title}
                </Link>
              ))}
            </div>
            <NextLink>Next</NextLink>
          </>
        )}
      </Pagination>
    );
  }

  const ALL_PRODUCTS_QUERY = `#graphql
    query AllProducts(
      $country: CountryCode
      $language: LanguageCode
      $first: Int
      $last: Int
      $startCursor: String
      $endCursor: String
    ) @inContext(country: $country, language: $language) {
      products(first: $first, last: $last, before: $startCursor, after: $endCursor) {
        nodes { id
          title
          handle
        }
        pageInfo {
          hasPreviousPage
          hasNextPage
          startCursor
          endCursor
        }
      }
    }
  `;
  ```

  ##### TypeScript

  ```tsx
  import {json, type LoaderFunctionArgs} from '@shopify/remix-oxygen';
  import {Pagination, getPaginationVariables} from '@shopify/hydrogen';
  import {useLoaderData, Link} from '@remix-run/react';
  import {ProductConnection} from '@shopify/hydrogen/storefront-api-types';

  export async function loader({
    request,
    context: {storefront},
  }: LoaderFunctionArgs) {
    const variables = getPaginationVariables(request, {pageBy: 8});

    const data = await storefront.query<{products: ProductConnection}>(
      ALL_PRODUCTS_QUERY,
      {
        variables,
      },
    );

    return json({products: data.products});
  }

  export default function List() {
    const {products} = useLoaderData<typeof loader>();

    return (
      <Pagination connection={products}>
        {({nodes, NextLink, PreviousLink}) => (
          <>
            <PreviousLink>Previous</PreviousLink>
            <div>
              {nodes.map((product) => (
                <Link key={product.id} to={`/products/${product.handle}`}>
                  {product.title}
                </Link>
              ))}
            </div>
            <NextLink>Next</NextLink>
          </>
        )}
      </Pagination>
    );
  }

  const ALL_PRODUCTS_QUERY = `#graphql
    query AllProducts(
      $country: CountryCode
      $language: LanguageCode
      $first: Int
      $last: Int
      $startCursor: String
      $endCursor: String
    ) @inContext(country: $country, language: $language) {
      products(first: $first, last: $last, before: $startCursor, after: $endCursor) {
        nodes { id
          title
          handle
        }
        pageInfo {
          hasPreviousPage
          hasNextPage
          startCursor
          endCursor
        }
      }
    }
  `;
  ```

## Related

[- getPaginationVariables](https://shopify.dev/docs/api/hydrogen/2023-10/utilities/getpaginationvariables)
