Pagination or infinite scroll
Use page numbers for records people come back to, a previous and next pair for data that moves, and a feed for browsing.
The problem
Infinite scroll on a table means people can't get back to row 140, can't reach the footer and can't share where they were. Page numbers on a live activity feed skip and repeat items as new ones arrive. The way people move through a list should match how they use it.
When to use it
Use it for
- Any list or table longer than one screen.
- Choosing how a list loads before the API is built: cursors and page numbers need different endpoints.
Not for
- Lists under about 50 items: show them all.
- Search results where people almost never go past the first page: show the best 10 to 20 and a better search.
Anatomy
- Page numbersPagination or TableFooter. For tables and records people find, share and come back to.
- JumpJumpToPage. For lists with more than about 20 pages.
- Previous and nextCursorPager. For data without stable pages, such as an activity log.
- FeedLoad more as people scroll, with FeedStatus at the bottom for loading, the end and errors.
How to build it
- Ask whether people look for a specific item or browse. Looking: pages. Browsing: a feed.
- Ask whether items move between pages while people read. If yes, use cursors: CursorPager or a feed.
- For pages, show the range (“11 to 20 of 128”) and keep the page in the URL.
- Add JumpToPage when there are more than about 20 pages.
- For feeds, show FeedStatus at the bottom: loading, “You've reached the end”, or an error with Retry.
- Never put essential links in a footer below an infinite list.
app.tsx
import { CursorPager, FeedStatus, TableFooter } from "@nexera-ui/react";
// Records people come back to
<TableFooter
aria-label="Employees pages"
range="11 to 20 of 128"
page={page}
pageCount={13}
onPageChange={setPage}
/>
// An activity log that changes while people read it
<CursorPager
aria-label="Activity pages"
context="Showing activity from 1 to 7 Oct"
onPrevious={loadNewer}
onNext={loadOlder}
/>
// The bottom of a feed
<FeedStatus status={hasMore ? "loading" : "end"} onRetry={loadMore}>
{hasMore ? "Loading more" : "You've reached the end · 128 employees"}
</FeedStatus>Accessibility
| Key | Action |
|---|---|
| Tab | Moves to Previous, the page numbers and Next. |
| Enter | Goes to the focused page, or the page typed into JumpToPage. |
- The current page has aria-current="page", and every page button is named “Page 3”.
- Changing page is announced, and focus moves to the top of the new results.
- Feeds announce new items politely and offer a button as well as scroll, for keyboard users.
Do and don't
DoUse page numbers for tables and keep the page in the URL.
Don'tInfinite-scroll a table people need to reference.
DoUse cursors when items move as new ones arrive.
Don'tUse page numbers on a live feed, so items repeat and disappear.
DoSay when a feed has ended.
Don'tLeave a spinner at the bottom forever.