Pagination

  • Use pagination to split long datasets like tables and lists
  • As a rule of thumb set pagination after 10, 15 or 20 items
  • Use small navigation on mobile and for small datasets

Normal

Page 1 of 20

Small

Page 1 of 20

Normal with multiple page sizes

10
Page 1 of 20

API

Full example

export default () => {
const PAGE_SIZE = 20;
const TOTAL_ITEMS = 200;
const [currentPage, setCurrentPage] = useState(1);
const lastPage = Math.ceil(TOTAL_ITEMS / PAGE_SIZE);
return (
<Pagination
value={currentPage}
pageSize={PAGE_SIZE}
totalItems={TOTAL_ITEMS}
label={
<Text weak>
Page{' '}
<Text as="b" fontWeight="semibold" weak>
{currentPage} of {lastPage}
</Text>
</Text>
}
onNextPage={() => setCurrentPage(current => current + 1)}
onPrevPage={() => setCurrentPage(current => current - 1)}
onSkipForward={() => setCurrentPage(lastPage)}
onSkipBackward={() => setCurrentPage(1)}
/>
);
};

Label

The label should be used to display the current state of the pagination which typically consists of the current page and the total number of pages. This can be as simple as passing a string:

Page 1 of 20
<Pagination
value={currentPage}
pageSize={PAGE_SIZE}
totalItems={TOTAL_ITEMS}
label={`Page ${currentPage} of ${Math.ceil(TOTAL_ITEMS / PAGE_SIZE)}`}
/>

To display a label like in the examples above you can pass a custom component:

Page 1 of 20
<Pagination
value={currentPage}
pageSize={PAGE_SIZE}
totalItems={TOTAL_ITEMS}
label={
<Text weak>
Page{' '}
<Text as="b" fontWeight="semibold" weak>
{currentPage} of {lastPage}
</Text>
</Text>
}
/>

Accessibility

It is recommended to set ARIA labels to provide accessible names for the pagination inputs. This also helps when testing. You can use the following props to provide translated ARIA labels.

<Pagination
ariaLabelFirst="First"
ariaLabelPrevious="Previous"
ariaLabelNext="Next"
ariaLabelLast="Last"
ariaLabelSelectPageSizeContainer="Select page size container" /* Only if you are using the `pageSizes` prop */
/>

Properties

NameTypeDefault
value (required)

number

Value of the current page. The first page has value 1.
pageSize (required)

number

Number of items per page.
totalItems (required)

number

Total number of items in the list.
size

"normal" | "small"

"normal"
label

React component or string

Label to display in the pagination container. Usually something like "Page X of Y".
pageSizes

{ label: string; value: string }[]

Array of options if page size can be changed by user.
onNextPage

() => void

Callback to call when the next page button is clicked.
onSkipForward

() => void

Callback to call when the move to the last page button is clicked.
onPrevPage

() => void

Callback to call when the previous page button is clicked.
onSkipBackward

() => void

Callback to call when the move to the first page button is clicked.
onSelectPageSize

(selected: { label: string; value: string }) => void

Callback to call a different page size was selected. Fired only if `pageSizes` prop is provided.
ariaLabelNext

string

Aria label for the next page button.
ariaLabelLast

string

Aria label for the last page page button.
ariaLabelPrevious

string

Aria label for the previous page page button.
ariaLabelFirst

string

Aria label for the "Move to the first page" button.
ariaLabelSelectPageSizeContainer

string

Aria label for the container with the page sizes selector.

Testing

In tests you can use the aria-label attributes to select the individual buttons. Here is an example using @testing-library/react.

You can see how to test the page sizes select in Wave's SelectList

test('should select by aria-label', () => {
const { getByRole } = render(<Pagination value={1} pageSize={20} totalItems={200} />);
expect(getByRole('button', { name: 'First' })).toBeInTheDocument();
expect(getByRole('button', { name: 'Previous' })).toBeInTheDocument();
expect(getByRole('button', { name: 'Next' })).toBeInTheDocument();
expect(getByRole('button', { name: 'Last' })).toBeInTheDocument();
});
Table of contents
APITesting