Pagination

Previous and next page buttons, with the range of items shown.

StableSince 1.0.0
On this page

Import

import { Pagination } from '@envsemble/envui';

Usage

<Pagination page={page} pageSize={60} total={245} pending={loading} onPageChange={setPage} />

page counts from 1 and is kept within the pages that exist. onPageChange receives the page before or after; the application loads it and passes it back as page. While it loads, set pending: the button pressed shows a spinner, also when the load starts in an effect.

Without a known total

total counts all items: the range ends with it, and the last page ends the list. Pass it once it is known. Without it, the range shows only the page's items, as in 61–120, and hasNextPage, true by default, says whether a later page exists, such as from a cursor's has more.

Names and the range

EnvUIProvider's locale formats the numbers. aria-label, previousLabel, nextLabel and formatRange set the names and the range for one pager: formatRange receives the first and last item shown, the total, the page and the page count.

const messages = {
  pagination: {
    label: 'Result pages',
    previous: 'Previous results',
    next: 'More results',
    range: ({ start, end, total }: { start: string; end: string; total?: string }) =>
      total === undefined ? `${start}–${end}` : `${start}–${end} of ${total} results`,
  },
};

<EnvUIProvider messages={messages}>
  <Pagination page={page} pageSize={20} total={1234} onPageChange={setPage} />
</EnvUIProvider>;

An application that translates passes the strings of the reader's language; the numbers follow the locale the provider inherits from the page.

Size and variant

size is sm, md or lg; without it, the buttons take their container's. variant is the buttons' look, as on IconButton: secondary by default, or text. hideWhenSinglePage renders nothing while every item fits on one page.

Composition

The pager is a nav, env-pagination, with the range, env-pagination-range, and the previous and next buttons, env-pagination-button, the next one last; a loading button shows the spinner, env-button-spinner. The end buttons stay focusable with aria-disabled where there is no page to go to.

Accessibility

You provide

  • An aria-label that names what it pages through, where a page has several navigation landmarks.
  • pending while a page loads, and the page itself.

envUI provides

  • A nav landmark named Pagination, with icon buttons named in tooltips.
  • aria-disabled on a button with no page to go to, and aria-busy on the one whose load runs.
  • The range as a polite live region, so the new range is announced once.

Props

Pagination

Compact pagination for toolbars: the range of items shown, such as 1–60 of 245, and icon buttons for the previous and next pages, in a navigation landmark. The application loads the pages; the range is announced as it changes, and focus stays on the button pressed.

PropTypeDescription
pagerequired
number
The page shown, counted from 1. It is kept within the pages that exist, so a page beyond the end shows the last one.
pageSizerequired
number
The most items a page shows, such as 60; at least 1.
total
number
All items, when known; the range then ends with it, as in 1–60 of 245, and the last page ends the list. Leave it out for a list read in batches, where hasNextPage says when it ends.
hasNextPageDefault true
boolean
Whether a later page exists, for a list without total, such as from a cursor's has more.
onPageChangerequired
(page: number) => void
Receives the page before or after the current one when its button is pressed. The application loads that page and passes it back as page.
pendingDefault false
boolean
A page is loading: the button pressed shows a spinner, also when the load starts in an effect after the page changes, and both buttons ignore presses while staying focusable. A load for another reason, such as a refresh, makes both wait without a spinner.
hideWhenSinglePageDefault false
boolean
Render nothing while every item fits on one page, so neither button has anywhere to go.
formatRangeDefault 1–60 of 245, or 61–120 without total, with numbers in the locale
(range: PaginationRange) => ReactNode
Writes the range from the first and last item shown, the total, the page and the page count, for one pager; EnvUIProvider's messages.pagination.range writes it for every pager.
previousLabelDefault 'Previous page', or EnvUIProvider's messages.pagination.previous
string
The previous button's accessible name and tooltip.
nextLabelDefault 'Next page', or EnvUIProvider's messages.pagination.next
string
The next button's accessible name and tooltip.
variantDefault 'secondary'
'primary''secondary''outline''ghost''text'
The buttons' variant, as on IconButton, such as text for a quiet toolbar.
size
'sm''md''lg'
The buttons' height, as on every control: sm, md or lg in the current scale. Without it, they take the control height of the container, md unless the container sets another.
aria-labelDefault 'Pagination', or EnvUIProvider's messages.pagination.label
string
The navigation landmark's name, such as Report pages, where a page has more than one.

Also accepts the native props of <nav>, such as ref, className and aria-* attributes.

Part names

Each part's class and state attributes are public and versioned, for an application's CSS to style.

env-pagination
The page buttons.
env-pagination-button
One page, previous or next button.
env-pagination-range
The range of items shown.
data-direction
next · previous on env-pagination-button
data-size
lg · md · sm

Strings

EnvUIProvider's messages overrides each, and a component's own label prop wins over it.

messages.pagination.label
"Pagination" Names the navigation.
messages.pagination.previous
"Previous page" The previous-page button's name.
messages.pagination.next
"Next page" The next-page button's name.
messages.pagination.range
({ start, end, total }) => string The shown range from its first and last item and the total, formatted in the locale: 1–60 of 245, 245 of 245 for a single item, or 61–120 without a total.

Changelog

1.0.0

The range's numbers are in the locale, EnvUIProvider's or the runtime's, instead of always English, and the names and the range come from messages.pagination; previousLabel, nextLabel, formatRange and aria-label still override them.