Ark UI Logo
Components
Pagination

Pagination

A navigation component that allows users to browse through pages.

Loading...

Anatomy

To set up the pagination correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Examples

Learn how to use the Pagination component in your project. Let's take a look at the most basic example:

import { Pagination } from '@ark-ui/react/pagination'

export const Basic = () => (
  <Pagination.Root count={5000} pageSize={10} siblingCount={2}>
    <Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
    <Pagination.Context>
      {(pagination) =>
        pagination.pages.map((page, index) =>
          page.type === 'page' ? (
            <Pagination.Item key={index} {...page}>
              {page.value}
            </Pagination.Item>
          ) : (
            <Pagination.Ellipsis key={index} index={index}>
              &#8230;
            </Pagination.Ellipsis>
          ),
        )
      }
    </Pagination.Context>
    <Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
  </Pagination.Root>
)

Controlled Pagination

To create a controlled Pagination component, manage the state of the current page using the page prop and update it when the onPageChange event handler is called:

import { Pagination } from '@ark-ui/react/pagination'
import { useState } from 'react'

export const Controlled = () => {
  const [currentPage, setCurrentPage] = useState(1)

  return (
    <Pagination.Root
      count={5000}
      pageSize={10}
      siblingCount={2}
      page={currentPage}
      onPageChange={(details) => setCurrentPage(details.page)}
    >
      <Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
      <Pagination.Context>
        {(pagination) =>
          pagination.pages.map((page, index) =>
            page.type === 'page' ? (
              <Pagination.Item key={index} {...page}>
                {page.value}
              </Pagination.Item>
            ) : (
              <Pagination.Ellipsis key={index} index={index}>
                &#8230;
              </Pagination.Ellipsis>
            ),
          )
        }
      </Pagination.Context>
      <Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
    </Pagination.Root>
  )
}

Customizing Pagination

You can customize the Pagination component by setting various props such as dir, pageSize, siblingCount, and translations. Here's an example of a customized Pagination:

import { Pagination } from '@ark-ui/react/pagination'

export const Customized = () => (
  <Pagination.Root
    count={5000}
    pageSize={20}
    siblingCount={3}
    translations={{
      nextTriggerLabel: 'Next',
      prevTriggerLabel: 'Prev',
      itemLabel: (details) => `Page ${details.page}`,
    }}
  >
    <Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>
    <Pagination.Context>
      {(pagination) =>
        pagination.pages.map((page, index) =>
          page.type === 'page' ? (
            <Pagination.Item key={index} {...page}>
              {page.value}
            </Pagination.Item>
          ) : (
            <Pagination.Ellipsis key={index} index={index}>
              &#8230;
            </Pagination.Ellipsis>
          ),
        )
      }
    </Pagination.Context>
    <Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
  </Pagination.Root>
)

Using Context

The Context component provides access to the pagination state and methods through a render prop pattern. This allows you to access methods like setPage, setPageSize, goToNextPage, goToPrevPage, goToFirstPage, goToLastPage, as well as properties like totalPages and pageRange.

import { Pagination } from '@ark-ui/react/pagination'

export const Context = () => {
  return (
    <Pagination.Root count={100} pageSize={10}>
      <Pagination.Context>
        {(pagination) => (
          <div>
            <button onClick={() => pagination.goToFirstPage()}>First</button>
            <button onClick={() => pagination.goToPrevPage()}>Previous</button>
            <button onClick={() => pagination.setPage(5)}>Go to Page 5</button>
            <button onClick={() => pagination.goToNextPage()}>Next</button>
            <button onClick={() => pagination.goToLastPage()}>Last</button>

            <p>
              Page {pagination.page} of {pagination.totalPages}
            </p>
            <p>
              Items {pagination.pageRange.start + 1}-{pagination.pageRange.end}
            </p>

            <button onClick={() => pagination.setPageSize(20)}>20 per page</button>
          </div>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}

Data Slicing

Use the slice() method to paginate actual data arrays. This method automatically slices your data based on the current page and page size.

import { Pagination } from '@ark-ui/react/pagination'

const items = Array.from({ length: 100 }, (_, i) => `Item ${i + 1}`)

export const DataSlicing = () => {
  return (
    <Pagination.Root count={items.length} pageSize={10}>
      <Pagination.Context>
        {(pagination) => (
          <div>
            <div>
              <h3>Current Page Items:</h3>
              <ul>
                {pagination.slice(items).map((item) => (
                  <li key={item}>{item}</li>
                ))}
              </ul>
            </div>

            <div>
              <Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>

              {pagination.pages.map((page, index) =>
                page.type === 'page' ? (
                  <Pagination.Item key={index} {...page}>
                    {page.value}
                  </Pagination.Item>
                ) : (
                  <Pagination.Ellipsis key={index} index={index}>
                    &#8230;
                  </Pagination.Ellipsis>
                ),
              )}

              <Pagination.NextTrigger>Next</Pagination.NextTrigger>
            </div>
          </div>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}

Page Range Display

Display the current page range information using the pageRange property. This shows which items are currently visible (e.g., "Showing 1-10 of 100 results").

import { Pagination } from '@ark-ui/react/pagination'

export const PageRange = () => {
  return (
    <Pagination.Root count={100} pageSize={10}>
      <Pagination.Context>
        {(pagination) => (
          <div>
            <div>
              <Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>

              {pagination.pages.map((page, index) =>
                page.type === 'page' ? (
                  <Pagination.Item key={index} {...page}>
                    {page.value}
                  </Pagination.Item>
                ) : (
                  <Pagination.Ellipsis key={index} index={index}>
                    &#8230;
                  </Pagination.Ellipsis>
                ),
              )}

              <Pagination.NextTrigger>Next</Pagination.NextTrigger>
            </div>

            <div>
              <p>
                Showing {pagination.pageRange.start + 1}-{pagination.pageRange.end} of {pagination.count} results
              </p>
              <p>
                Page {pagination.page} of {pagination.totalPages}
              </p>
            </div>
          </div>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}

Page Size Control

Control the number of items per page dynamically using setPageSize(). This example shows how to integrate a native select element to change the page size.

import { Pagination } from '@ark-ui/react/pagination'

export const PageSizeControl = () => {
  return (
    <Pagination.Root count={100} pageSize={10}>
      <Pagination.Context>
        {(pagination) => (
          <div>
            <div>
              <label>Items per page: </label>
              <select value={pagination.pageSize} onChange={(e) => pagination.setPageSize(Number(e.target.value))}>
                <option value={5}>5</option>
                <option value={10}>10</option>
                <option value={20}>20</option>
                <option value={50}>50</option>
              </select>
            </div>

            <div>
              <Pagination.PrevTrigger>Previous</Pagination.PrevTrigger>

              {pagination.pages.map((page, index) =>
                page.type === 'page' ? (
                  <Pagination.Item key={index} {...page}>
                    {page.value}
                  </Pagination.Item>
                ) : (
                  <Pagination.Ellipsis key={index} index={index}>
                    &#8230;
                  </Pagination.Ellipsis>
                ),
              )}

              <Pagination.NextTrigger>Next</Pagination.NextTrigger>
            </div>

            <p>
              Page {pagination.page} of {pagination.totalPages}
            </p>
          </div>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}

Create pagination with link navigation for better SEO and accessibility. This example shows how to use the pagination component with anchor links instead of buttons.

import { Pagination, usePagination } from '@ark-ui/react/pagination'

export const Link = () => {
  const pagination = usePagination({
    type: 'link',
    count: 100,
    pageSize: 10,
    siblingCount: 2,
  })

  const getHref = (page: number | null) => (page != null ? `/page=${page}` : '/')

  return (
    <Pagination.RootProvider value={pagination}>
      <a {...pagination.getPrevTriggerProps()} href={getHref(pagination.previousPage)}>
        Previous
      </a>
      {pagination.pages.map((page, index) =>
        page.type === 'page' ? (
          <a key={index} {...pagination.getItemProps(page)} href={getHref(page.value)}>
            {page.value}
          </a>
        ) : (
          <span key={index} {...pagination.getEllipsisProps({ index })}>
            &#8230;
          </span>
        ),
      )}
      <a {...pagination.getNextTriggerProps()} href={getHref(pagination.nextPage)}>
        Next
      </a>
    </Pagination.RootProvider>
  )
}

Root Provider

The RootProvider component provides a context for the pagination. It accepts the value of the usePagination hook. You can leverage it to access the component state and methods from outside the pagination.

import { Pagination, usePagination } from '@ark-ui/react/pagination'

export const RootProvider = () => {
  const pagination = usePagination({ count: 5000, pageSize: 10, siblingCount: 2 })

  return (
    <>
      <button onClick={() => pagination.goToNextPage()}>Next Page</button>

      <Pagination.RootProvider value={pagination}>
        <Pagination.PrevTrigger>Previous Page</Pagination.PrevTrigger>
        <Pagination.Context>
          {(pagination) =>
            pagination.pages.map((page, index) =>
              page.type === 'page' ? (
                <Pagination.Item key={index} {...page}>
                  {page.value}
                </Pagination.Item>
              ) : (
                <Pagination.Ellipsis key={index} index={index}>
                  &#8230;
                </Pagination.Ellipsis>
              ),
            )
          }
        </Pagination.Context>
        <Pagination.NextTrigger>Next Page</Pagination.NextTrigger>
      </Pagination.RootProvider>
    </>
  )
}

If you're using the RootProvider component, you don't need to use the Root component.

API Reference

Root

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
count
number

Total number of data items

defaultPage1
number

The initial active page when rendered. Use when you don't need to control the active page of the pagination.

defaultPageSize10
number

The initial number of data items per page when rendered. Use when you don't need to control the page size of the pagination.

ids
Partial<{ root: string ellipsis: (index: number) => string prevTrigger: string nextTrigger: string item: (page: number) => string }>

The ids of the elements in the accordion. Useful for composition.

onPageChange
(details: PageChangeDetails) => void

Called when the page number is changed

onPageSizeChange
(details: PageSizeChangeDetails) => void

Called when the page size is changed

page
number

The controlled active page

pageSize
number

The controlled number of data items per page

siblingCount1
number

Number of pages to show beside active page

translations
IntlTranslations

Specifies the localized strings that identifies the accessibility elements and their states

type'button'
'button' | 'link'

The type of the trigger element

Ellipsis

PropDefaultType
index
number

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

Item

PropDefaultType
type
'page'

value
number

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]pagination
[data-part]item
[data-index]The index of the item
[data-selected]Present when selected

NextTrigger

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]pagination
[data-part]next-trigger
[data-disabled]Present when disabled

PrevTrigger

PropDefaultType
asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
Data AttributeValue
[data-scope]pagination
[data-part]prev-trigger
[data-disabled]Present when disabled

RootProvider

PropDefaultType
value
UsePaginationReturn

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.