Paginator
A navigation element for large data sets or long lists divided into multiple pages.
The Basics
What it is
Pagination is the process of dividing content into multiple “pages” for display on a single web page. Paginator enables users to navigate between these pages. It displays a row of navigable numbers for the pages of content, including one for the final page, so that users know the total number. Paginator allows users to page through sequentially or jump to a specific page.
How it works
- When a web page that includes Paginator loads, it defaults to page 1.
- To navigate to page 2, the user activates the right arrow (for “next”) or “2” button via the Space bar or mouse.
- To return to page 1, the user activates the left arrow (for “previous”) or the “1” button.
- On page 1, the left arrow is disabled (as there are no previous pages).
- To navigate to a non-sequential page, the user activates the button for that page via the Tab key or mouse, or enters a number in the page input (depending on the Paginator variation used).
- On the last page, the right arrow is disabled (as there are no next pages).
When to use
- To implement navigation for large data sets or lists (e.g., search results, tables, reports)
When not to use
- For web pages that use continuous scroll
- To navigate among separate web pages
What to use instead
Use Tabs for on-page navigation between content sections.
Use Menu for navigation between web pages.
Use Tree for vertical navigation between web pages.
How to use
Paginator can be used for a known number of pages, but it also works for data sets or lists with an unknown number of pages. This is helpful when using “lazy loading” for data to speed up initial page load.
Variations
Paginator’s variations require progressively more space but offer additional functionality.
Compact
- Smallest, with fewest features
- Displays current page and total pages
- Enables navigation to next and previous pages
- Best for mobile or other narrow frames
Default
- Wider, with added features
- Displays current page and total pages
- Enables navigation to first, last, next, and previous pages
- Best for most use cases
Default with page jump
- Widest, with all features
- Displays current page and total pages
- Enables navigation to first, last, next, and previous pages, or to any page via text input
- Best for very long content, or if users may want to jump directly to a specific page
Page count and effect on interface
Depending on the number of pages, the default and default with page jump variations display page information differently:
- 7 or fewer pages: Buttons for all the pages are displayed.
- More than 7 pages: Some page buttons are replaced by ellipses. The first, last, next, and previous pages are always displayed.
- Unknown or infinite pages: An ellipsis appears after the first, previous, and next page buttons (but before the right arrow) to indicate that there are more pages.
Style
Design details
No additional information for this component.
Placement and hierarchy
Paginator is typically right-aligned at the top of the content page or block.
For workflows where users are likely to scroll from top to bottom and then immediately go to the next page, Paginator can appear at the bottom of the content page instead.
If the workflow involves scrolling up and down the page, make Paginator sticky (fixed) for easier access. If making it sticky isn’t possible, consider including Paginator both above and below the content.
Content
Paginator content can’t be customized. Pages are represented by numbers only, and use of any other characters or icons for the arrow controls is off-limits. The label text for the “Jump to” input is also fixed.
Screen readers
All navigation arrows and page numbers include an aria-label attribute that describes the action that will take place when activated (e.g., “Previous page”, “Go to page 3”). Additionally, the screen reader states which page is currently in use (e.g., “You are on page 2”).
Demos
Coding
Developer tips
Note that the selectedIndex
prop is zero-indexed, while page labels start with “1”. This means selectedIndex={0}
displays a highlighted “1”, selectedIndex={1}
displays a highlighted “2”, and so on.
The function passed to the onSelectedIndexChange
prop has the signature (index) => { }
, where index
is the changed selected index. The body of the function should have any state changes or side effects.
Repository
Implementation links
Paginator directory in Bitbucket
Implementation details
It is strongly recommended to familiarize yourself with the Forge source code. While this documentation is a best effort to document the intent and usage of a component, sometimes some features only become clear when looking at the source code. Also, looking at Forge's source code may help identify and fix bugs in either your application or Forge itself.
Storybook files
Forge maintains at least one storybook file per component. While the primary audience for these files is typically the Forge team, these storybook files may cover usages of the component not covered by a demo. The storybook for the latest version of forge can be found at go/forge-storybook.
Testing library
Forge strongly encourages using testing-library to write tests for your application.
"The more your tests resemble the way your software is used, the more confidence they can give you."
If you're having trouble testing a Forge component using testing-library, it would be a good idea to see how Forge tests its own components. For the most part, Forge tries to use screen.getByRole as much as it can, as that API provides the best feedback on a11y compliance. Forge discourages the use of document.querySelector and screen.getByTestId as both APIs encourage using implementation details to test your component, and discourage adding roles to your component.
With that being said, many of Forge's components were not built with accessibility in mind. These components do break the recommendations listed above.
Import statements
In Nimbus applications
athenaOne serves the Forge bundle independently from your application's bundle. Importing Forge components directly from '@athena/forge'
takes advantage of this feature.
import { Paginator } from '@athena/forge'
In standalone applications
Importing components using the exact path to the module takes advantage of webpack's tree shaking feature. Webpack will include only that module and its dependencies.
import Paginator from '@athena/forge/Paginator';
To use this import guidance, Typescript applications must use typescript >= 4.7.3
, and should add this setting to their tsconfig.json file:
{"compilerOptions": {"moduleResolution": "Node16",}}
If this setting doesn't work for your application, use this import statement instead:
import Paginator from '@athena/forge/dist/Paginator';