# 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)