# Pagination 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. ```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 ( {({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 } } } `; ``` ```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(); 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 } } } `; ``` ## Props ### PaginationProps ### connection value: `Connection` 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 value: `PaginationRenderProp` A render prop that includes pagination data and helpers. ### PaginationRenderProp #### Returns: ReactNode #### Params: - props: PaginationInfo type PaginationRenderProp = ( props: PaginationInfo, ) => ReactNode; ### PaginationInfo ### nodes value: `Array` The paginated array of nodes. You should map over and render this array. ### NextLink value: `(props: Omit & { ref?: Ref; }) => ReactNode` The `` is a helper component that makes it easy to navigate to the next page of paginated data. Alternatively you can build your own `` component: `` ### PreviousLink value: `(props: Omit & { ref?: Ref; }) => ReactNode` The `` is a helper component that makes it easy to navigate to the previous page of paginated data. Alternatively you can build your own `` component: `` ### previousPageUrl value: `string` The URL to the previous page of paginated data. Use this prop to build your own `` component. ### nextPageUrl value: `string` The URL to the next page of paginated data. Use this prop to build your own `` component. ### hasNextPage value: `boolean` True if the cursor has next paginated data ### hasPreviousPage value: `boolean` True if the cursor has previous paginated data ### isLoading value: `boolean` True if we are in the process of fetching another page of data ### state value: `{ nodes: NodesType[]; pageInfo: { endCursor: string; startCursor: string; hasPreviousPage: boolean; }; }` The `state` property is important to use when building your own `` 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 `` component. ## Related - [getPaginationVariables](https://shopify.dev/docs/api/hydrogen/2023-10/utilities/getpaginationvariables)