--- title: Pagination description: The [Storefront API uses cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate through lists of data and the `` 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 `` component provides a render prop with properties to load more elements into your list. api_version: 2025-07 api_name: hydrogen source_url: html: https://shopify.dev/docs/api/hydrogen/latest/components/pagination md: https://shopify.dev/docs/api/hydrogen/latest/components/pagination.md --- # Paginationcomponent The [Storefront API uses cursors](https://shopify.dev/docs/api/usage/pagination-graphql) to paginate through lists of data and the `` 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 `` component provides a render prop with properties to load more elements into your list. ## Props * children PaginationRenderProp\ required A render prop that includes pagination data and helpers. * connection Connection\ 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. * namespace string A namespace for the pagination component to avoid URL param conflicts when using multiple `Pagination` components on a single page. ### PaginationRenderProp * contextTypes ```ts ValidationMap | undefined ``` * defaultProps Used to define default values for the props accepted by the component. ```ts Partial

| undefined ``` * displayName Used in debugging messages. You might want to set it explicitly if you want to display a different name for debugging purposes. ```ts string | undefined ``` * propTypes Used to declare the types of the props accepted by the component. These types will be checked during rendering and in development only. We recommend using TypeScript instead of checking prop types at runtime. ```ts WeakValidationMap

| undefined ``` ```ts FC> ``` ### Connection ```ts { nodes: Array; pageInfo: PageInfo; } | { edges: Array<{ node: NodesType; }>; pageInfo: PageInfo; } ``` ### Examples * #### Example code ##### Description I am the default example ##### JavaScript ```jsx import {Pagination, getPaginationVariables} from '@shopify/hydrogen'; import {useLoaderData, Link} from 'react-router'; export async function loader({request, context: {storefront}}) { const variables = getPaginationVariables(request, {pageBy: 8}); const data = await storefront.query(ALL_PRODUCTS_QUERY, { variables, }); return {products: data.products}; } export default function List() { const {products} = useLoaderData(); return ( {({nodes, PreviousLink, NextLink}) => ( <> Previous

{nodes.map((product) => ( {product.title} ))}
Next )}
); } 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 {type LoaderFunctionArgs} from '@shopify/remix-oxygen'; import {Pagination, getPaginationVariables} from '@shopify/hydrogen'; import {useLoaderData, Link} from 'react-router'; 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 {products: data.products}; } export default function List() { const {products} = useLoaderData(); return ( {({nodes, NextLink, PreviousLink}) => ( <> Previous
{nodes.map((product) => ( {product.title} ))}
Next )}
); } 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 } } } `; ``` ## Examples Other examples using the `Pagination` component. ### Multiple \`Pagination\` components on a single page Example Use the `namespace` prop to differentiate between multiple `Pagination` components on a single page ### Examples * #### Example ##### Description Use the \`namespace\` prop to differentiate between multiple \`Pagination\` components on a single page ##### JavaScript ```jsx import {useLoaderData, Link} from 'react-router'; import {getPaginationVariables, Pagination} from '@shopify/hydrogen'; export async function loader({request, context: {storefront}}) { const womensPaginationVariables = getPaginationVariables(request, { pageBy: 2, namespace: 'womens', // Specify a unique namespace for the pagination parameters }); const mensPaginationVariables = getPaginationVariables(request, { pageBy: 2, namespace: 'mens', // Specify a unique namespace for the pagination parameters }); const [womensProducts, mensProducts] = await Promise.all([ storefront.query(COLLECTION_PRODUCTS_QUERY, { variables: {...womensPaginationVariables, handle: 'women'}, }), storefront.query(COLLECTION_PRODUCTS_QUERY, { variables: {...mensPaginationVariables, handle: 'men'}, }), ]); return {womensProducts, mensProducts}; } export default function Collection() { const {womensProducts, mensProducts} = useLoaderData(); return (

Womens

{({nodes, isLoading, PreviousLink, NextLink}) => { return (
{isLoading ? 'Loading...' : ↑ Load previous}
{nodes.map((product) => (
{product.title}
))}
{isLoading ? 'Loading...' : Load more ↓}
); }}

Mens

{({nodes, isLoading, PreviousLink, NextLink}) => { return (
{isLoading ? 'Loading...' : ↑ Load previous}
{nodes.map((product) => (
{product.title}
))}
{isLoading ? 'Loading...' : Load more ↓}
); }}
); } const COLLECTION_PRODUCTS_QUERY = `#graphql query CollectionProducts( $first: Int $last: Int $startCursor: String $endCursor: String $handle: String! ) { collection(handle: $handle) { products(first: $first, last: $last, before: $startCursor, after: $endCursor) { nodes { id handle title } pageInfo { hasPreviousPage hasNextPage startCursor endCursor } } } } `; ``` ##### TypeScript ```tsx import {type LoaderFunctionArgs} from '@shopify/remix-oxygen'; import {useLoaderData, Link} from 'react-router'; import {getPaginationVariables, Pagination} from '@shopify/hydrogen'; import {type Collection} from '@shopify/hydrogen-react/storefront-api-types'; export async function loader({ request, context: {storefront}, }: LoaderFunctionArgs) { const womensPaginationVariables = getPaginationVariables(request, { pageBy: 2, namespace: 'womens', // Specify a unique namespace for the pagination parameters }); const mensPaginationVariables = getPaginationVariables(request, { pageBy: 2, namespace: 'mens', // Specify a unique namespace for the pagination parameters }); const [womensProducts, mensProducts] = await Promise.all([ storefront.query<{collection: Collection}>(COLLECTION_PRODUCTS_QUERY, { variables: {...womensPaginationVariables, handle: 'women'}, }), storefront.query<{collection: Collection}>(COLLECTION_PRODUCTS_QUERY, { variables: {...mensPaginationVariables, handle: 'men'}, }), ]); return {womensProducts, mensProducts}; } export default function Collection() { const {womensProducts, mensProducts} = useLoaderData(); return (

Womens

{({nodes, isLoading, PreviousLink, NextLink}) => { return (
{isLoading ? 'Loading...' : ↑ Load previous}
{nodes.map((product) => (
{product.title}
))}
{isLoading ? 'Loading...' : Load more ↓}
); }}

Mens

{({nodes, isLoading, PreviousLink, NextLink}) => { return (
{isLoading ? 'Loading...' : ↑ Load previous}
{nodes.map((product) => (
{product.title}
))}
{isLoading ? 'Loading...' : Load more ↓}
); }}
); } const COLLECTION_PRODUCTS_QUERY = `#graphql query CollectionProducts( $first: Int $last: Int $startCursor: String $endCursor: String $handle: String! ) { collection(handle: $handle) { products(first: $first, last: $last, before: $startCursor, after: $endCursor) { nodes { id handle title } pageInfo { hasPreviousPage hasNextPage startCursor endCursor } } } } ` as const; ``` ## Related [- getPaginationVariables](https://shopify.dev/docs/api/hydrogen/utilities/getpaginationvariables)