# Pagination

URL: https://ark-ui.com/docs/components/pagination
LLM: https://ark-ui.com/llms.txt/components/pagination

A navigation component that allows users to browse through pages.

---



## Anatomy



```tsx
<Pagination.Root>
  <Pagination.PrevTrigger />
  <Pagination.Item />
  <Pagination.Ellipsis />
  <Pagination.NextTrigger />
</Pagination.Root>
```

## Examples

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

export const Basic = () => (
  <Pagination.Root count={5000} pageSize={10} siblingCount={2} className={styles.Root}>
    <div className={styles.Controls}>
      <Pagination.PrevTrigger className={styles.Trigger}>
        <ChevronLeftIcon />
      </Pagination.PrevTrigger>
      <Pagination.Context>
        {(pagination) =>
          pagination.pages.map((page, index) =>
            page.type === 'page' ? (
              <Pagination.Item key={index} {...page} className={styles.Item}>
                {page.value}
              </Pagination.Item>
            ) : (
              <Pagination.Ellipsis key={index} index={index} className={styles.Ellipsis}>
                &#8230;
              </Pagination.Ellipsis>
            ),
          )
        }
      </Pagination.Context>
      <Pagination.NextTrigger className={styles.Trigger}>
        <ChevronRightIcon />
      </Pagination.NextTrigger>
    </div>
  </Pagination.Root>
)
```

### Controlled

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:

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { useState } from 'react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

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

  return (
    <Pagination.Root
      count={5000}
      pageSize={10}
      siblingCount={2}
      page={currentPage}
      onPageChange={(details) => setCurrentPage(details.page)}
      className={styles.Root}
    >
      <div className={styles.Controls}>
        <Pagination.PrevTrigger className={styles.Trigger}>
          <ChevronLeftIcon />
        </Pagination.PrevTrigger>
        <Pagination.Context>
          {(pagination) =>
            pagination.pages.map((page, index) =>
              page.type === 'page' ? (
                <Pagination.Item key={index} {...page} className={styles.Item}>
                  {page.value}
                </Pagination.Item>
              ) : (
                <Pagination.Ellipsis key={index} index={index} className={styles.Ellipsis}>
                  &#8230;
                </Pagination.Ellipsis>
              ),
            )
          }
        </Pagination.Context>
        <Pagination.NextTrigger className={styles.Trigger}>
          <ChevronRightIcon />
        </Pagination.NextTrigger>
      </div>
    </Pagination.Root>
  )
}
```

### Root Provider

An alternative way to control the pagination is to use the `RootProvider` component and the `usePagination` hook. This
way you can access the state and methods from outside the component.

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination, usePagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

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

  return (
    <div className="stack">
      <button className={styles.Trigger} onClick={() => pagination.goToNextPage()}>
        Next Page
      </button>

      <Pagination.RootProvider value={pagination} className={styles.Root}>
        <div className={styles.Controls}>
          <Pagination.PrevTrigger className={styles.Trigger}>
            <ChevronLeftIcon />
          </Pagination.PrevTrigger>
          <Pagination.Context>
            {(pagination) =>
              pagination.pages.map((page, index) =>
                page.type === 'page' ? (
                  <Pagination.Item key={index} {...page} className={styles.Item}>
                    {page.value}
                  </Pagination.Item>
                ) : (
                  <Pagination.Ellipsis key={index} index={index} className={styles.Ellipsis}>
                    &#8230;
                  </Pagination.Ellipsis>
                ),
              )
            }
          </Pagination.Context>
          <Pagination.NextTrigger className={styles.Trigger}>
            <ChevronRightIcon />
          </Pagination.NextTrigger>
        </div>
      </Pagination.RootProvider>
    </div>
  )
}
```

### Customization

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:

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

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

### Context

Access pagination state and methods with `Pagination.Context` or the `usePaginationContext` hook. You get methods like
`setPage`, `setPageSize`, `goToNextPage`, `goToPrevPage`, `goToFirstPage`, `goToLastPage`, as well as properties like
`totalPages` and `pageRange`.

```tsx
import { ChevronLeftIcon, ChevronRightIcon, ChevronsLeftIcon, ChevronsRightIcon } from 'lucide-react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

export const Context = () => {
  return (
    <Pagination.Root count={100} pageSize={10} className={styles.Root}>
      <Pagination.Context>
        {(pagination) => (
          <div className={styles.Controls}>
            <button className={styles.Trigger} onClick={() => pagination.goToFirstPage()}>
              <ChevronsLeftIcon />
            </button>
            <button className={styles.Trigger} onClick={() => pagination.goToPrevPage()}>
              <ChevronLeftIcon />
            </button>
            <p className={styles.Text} style={{ minWidth: '120px', textAlign: 'center' }}>
              Page {pagination.page} of {pagination.totalPages}
            </p>
            <button className={styles.Trigger} onClick={() => pagination.goToNextPage()}>
              <ChevronRightIcon />
            </button>
            <button className={styles.Trigger} onClick={() => pagination.goToLastPage()}>
              <ChevronsRightIcon />
            </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.

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

const users = [
  { id: 1, name: 'Emma Wilson', email: 'emma@example.com' },
  { id: 2, name: 'Liam Johnson', email: 'liam@example.com' },
  { id: 3, name: 'Olivia Brown', email: 'olivia@example.com' },
  { id: 4, name: 'Noah Davis', email: 'noah@example.com' },
  { id: 5, name: 'Ava Martinez', email: 'ava@example.com' },
  { id: 6, name: 'Ethan Garcia', email: 'ethan@example.com' },
  { id: 7, name: 'Sophia Rodriguez', email: 'sophia@example.com' },
  { id: 8, name: 'Mason Lee', email: 'mason@example.com' },
  { id: 9, name: 'Isabella Walker', email: 'isabella@example.com' },
  { id: 10, name: 'James Hall', email: 'james@example.com' },
  { id: 11, name: 'Mia Allen', email: 'mia@example.com' },
  { id: 12, name: 'Benjamin Young', email: 'benjamin@example.com' },
  { id: 13, name: 'Charlotte King', email: 'charlotte@example.com' },
  { id: 14, name: 'William Wright', email: 'william@example.com' },
  { id: 15, name: 'Amelia Scott', email: 'amelia@example.com' },
  { id: 16, name: 'Henry Green', email: 'henry@example.com' },
  { id: 17, name: 'Harper Adams', email: 'harper@example.com' },
  { id: 18, name: 'Sebastian Baker', email: 'sebastian@example.com' },
  { id: 19, name: 'Evelyn Nelson', email: 'evelyn@example.com' },
  { id: 20, name: 'Jack Carter', email: 'jack@example.com' },
]

export const DataSlicing = () => {
  return (
    <Pagination.Root count={users.length} pageSize={5} className={styles.Root}>
      <Pagination.Context>
        {(pagination) => (
          <>
            <div className={styles.Grid}>
              {pagination.slice(users).map((user) => (
                <div key={user.id} className={styles.GridItem}>
                  <span className={styles.GridItemTitle}>{user.name}</span>
                  <span className={styles.GridItemText}>{user.email}</span>
                </div>
              ))}
            </div>

            <div className={styles.Controls}>
              <Pagination.PrevTrigger className={styles.Trigger}>
                <ChevronLeftIcon />
              </Pagination.PrevTrigger>

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

              <Pagination.NextTrigger className={styles.Trigger}>
                <ChevronRightIcon />
              </Pagination.NextTrigger>
            </div>
          </>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}
```

### Page Range

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").

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

export const PageRange = () => {
  return (
    <Pagination.Root count={100} pageSize={10} className={styles.Root}>
      <Pagination.Context>
        {(pagination) => (
          <>
            <div className={styles.Controls}>
              <Pagination.PrevTrigger className={styles.Trigger}>
                <ChevronLeftIcon />
              </Pagination.PrevTrigger>

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

              <Pagination.NextTrigger className={styles.Trigger}>
                <ChevronRightIcon />
              </Pagination.NextTrigger>
            </div>

            <div className="stack">
              <p className={styles.Text}>
                Showing {pagination.pageRange.start + 1}-{pagination.pageRange.end} of {pagination.count} results
              </p>
              <p className={styles.Text}>
                Page {pagination.page} of {pagination.totalPages}
              </p>
            </div>
          </>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}
```

### Page Size

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.

> **Note:** For uncontrolled behavior, use `defaultPageSize` to set the initial value. For controlled behavior, use
> `pageSize` and `onPageSizeChange` to programmatically manage the page size.

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

export const PageSizeControl = () => {
  return (
    <Pagination.Root count={100} defaultPageSize={10} className={styles.Root}>
      <Pagination.Context>
        {(pagination) => (
          <>
            <div className="hstack">
              <label className={styles.Text}>Items per page:</label>
              <select
                className={styles.PageSizeSelect}
                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 className={styles.Controls}>
              <Pagination.PrevTrigger className={styles.Trigger}>
                <ChevronLeftIcon />
              </Pagination.PrevTrigger>

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

              <Pagination.NextTrigger className={styles.Trigger}>
                <ChevronRightIcon />
              </Pagination.NextTrigger>
            </div>

            <p className={styles.Text}>
              Page {pagination.page} of {pagination.totalPages}
            </p>
          </>
        )}
      </Pagination.Context>
    </Pagination.Root>
  )
}
```

### Links

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.

```tsx
import { ChevronLeftIcon, ChevronRightIcon } from 'lucide-react'
import { Pagination, usePagination } from '@ark-ui/react/pagination'
import styles from 'styles/pagination.module.css'

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

  return (
    <Pagination.RootProvider value={pagination} className={styles.Root}>
      <div className={styles.Controls}>
        <a className={styles.Trigger} {...pagination.getPrevTriggerProps()}>
          <ChevronLeftIcon />
        </a>
        {pagination.pages.map((page, index) =>
          page.type === 'page' ? (
            <a key={index} className={styles.Item} {...pagination.getItemProps(page)}>
              {page.value}
            </a>
          ) : (
            <span key={index} className={styles.Ellipsis} {...pagination.getEllipsisProps({ index })}>
              &#8230;
            </span>
          ),
        )}
        <a className={styles.Trigger} {...pagination.getNextTriggerProps()}>
          <ChevronRightIcon />
        </a>
      </div>
    </Pagination.RootProvider>
  )
}
```

## API Reference

### Props

### Root

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

**`boundaryCount`**
Type: `number`
Required: false
Default Value: `1`
Description: Number of pages to show at the beginning and end

**`count`**
Type: `number`
Required: false
Default Value: `undefined`
Description: Total number of data items

**`defaultPage`**
Type: `number`
Required: false
Default Value: `1`
Description: The initial active page when rendered.
Use when you don't need to control the active page of the pagination.

**`defaultPageSize`**
Type: `number`
Required: false
Default Value: `10`
Description: The initial number of data items per page when rendered.
Use when you don't need to control the page size of the pagination.

**`getPageUrl`**
Type: `(details: PageUrlDetails) => string`
Required: false
Default Value: `undefined`
Description: Function to generate href attributes for pagination links.
Only used when `type` is set to "link".

**`ids`**
Type: `Partial<{
  root: string
  ellipsis: (index: number) => string
  firstTrigger: string
  prevTrigger: string
  nextTrigger: string
  lastTrigger: string
  item: (page: number) => string
}>`
Required: false
Default Value: `undefined`
Description: The ids of the elements in the accordion. Useful for composition.

**`onPageChange`**
Type: `(details: PageChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Called when the page number is changed

**`onPageSizeChange`**
Type: `(details: PageSizeChangeDetails) => void`
Required: false
Default Value: `undefined`
Description: Called when the page size is changed

**`page`**
Type: `number`
Required: false
Default Value: `undefined`
Description: The controlled active page

**`pageSize`**
Type: `number`
Required: false
Default Value: `undefined`
Description: The controlled number of data items per page

**`siblingCount`**
Type: `number`
Required: false
Default Value: `1`
Description: Number of pages to show beside active page

**`translations`**
Type: `IntlTranslations`
Required: false
Default Value: `undefined`
Description: Specifies the localized strings that identifies the accessibility elements and their states

**`type`**
Type: `'button' | 'link'`
Required: false
Default Value: `"button"`
Description: The type of the trigger element

### Ellipsis

#### Props

**`index`**
Type: `number`
Required: true
Default Value: `undefined`
Description: undefined

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### FirstTrigger

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: pagination
**`data-part`**: first-trigger
**`data-disabled`**: Present when disabled

### Item

#### Props

**`type`**
Type: `'page'`
Required: true
Default Value: `undefined`
Description: undefined

**`value`**
Type: `number`
Required: true
Default Value: `undefined`
Description: undefined

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: pagination
**`data-part`**: item
**`data-index`**: The index of the item
**`data-selected`**: Present when selected

### LastTrigger

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: pagination
**`data-part`**: last-trigger
**`data-disabled`**: Present when disabled

### NextTrigger

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: pagination
**`data-part`**: next-trigger
**`data-disabled`**: Present when disabled

### PrevTrigger

#### Props

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

#### Data Attributes

**`data-scope`**: pagination
**`data-part`**: prev-trigger
**`data-disabled`**: Present when disabled

### RootProvider

#### Props

**`value`**
Type: `UsePaginationReturn`
Required: true
Default Value: `undefined`
Description: undefined

**`asChild`**
Type: `boolean`
Required: false
Default Value: `undefined`
Description: Use the provided child element as the default rendered element, combining their props and behavior.

### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `page` | `number` | The current page. |
| `count` | `number` | The total number of data items. |
| `pageSize` | `number` | The number of data items per page. |
| `totalPages` | `number` | The total number of pages. |
| `pages` | `Pages` | The page range. Represented as an array of page numbers (including ellipsis) |
| `previousPage` | `number | null` | The previous page. |
| `nextPage` | `number | null` | The next page. |
| `pageRange` | `PageRange` | The page range. Represented as an object with `start` and `end` properties. |
| `slice` | `<V>(data: V[]) => V[]` | Function to slice an array of data based on the current page. |
| `setPageSize` | `(size: number) => void` | Function to set the page size. |
| `setPage` | `(page: number) => void` | Function to set the current page. |
| `goToNextPage` | `VoidFunction` | Function to go to the next page. |
| `goToPrevPage` | `VoidFunction` | Function to go to the previous page. |
| `goToFirstPage` | `VoidFunction` | Function to go to the first page. |
| `goToLastPage` | `VoidFunction` | Function to go to the last page. |
