Theme studio

Design a theme, preview it live, then export it. Saved in this browser.

Quick picks #10b981
Generated scale
50100200300400500600700800900
Some text is below AA

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

  1. Page numbersPagination or TableFooter. For tables and records people find, share and come back to.
  2. JumpJumpToPage. For lists with more than about 20 pages.
  3. Previous and nextCursorPager. For data without stable pages, such as an activity log.
  4. FeedLoad more as people scroll, with FeedStatus at the bottom for loading, the end and errors.

How to build it

  1. Ask whether people look for a specific item or browse. Looking: pages. Browsing: a feed.
  2. Ask whether items move between pages while people read. If yes, use cursors: CursorPager or a feed.
  3. For pages, show the range (“11 to 20 of 128”) and keep the page in the URL.
  4. Add JumpToPage when there are more than about 20 pages.
  5. For feeds, show FeedStatus at the bottom: loading, “You've reached the end”, or an error with Retry.
  6. 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

Keyboard support
KeyAction
TabMoves to Previous, the page numbers and Next.
EnterGoes 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.