Pagination versus infinite scroll is usually argued as a taste question and decided by whichever the framework made easier. It is actually a task question, and the task has a tell: whether the reader is browsing or looking for something.
Someone browsing a feed wants the next thing without asking. Someone looking for a specific row wants to know how many there are, to jump, and to come back to the same place tomorrow. Those are different components.
Numbered pagination
The right default for anything a reader searches, sorts or returns to. Pagination by shadcn is the base with page navigation and previous and next links, Numbered Pagination and the usePagination hook by originui cover the logic, and Pagination by sean0205 is the responsive variant. Wheel Pagination by Ruixen UI is the unusual one.
What makes it work is the part people skip: the page belongs in the URL. ?page=3 means the reader can link to it, refresh it, open it in a new tab, and reach it again after the back button. A page number in React state has none of that, and a crawler sees only page one, which is how large catalogues end up with most of their inventory unreachable.
Two more details. Show the total, or at least whether there is a next page, because "1 of 47" answers a question that "Next" does not. And keep the page size stable, since a reader who has learned that row 40 is on page two will not forgive it moving.
Infinite scroll
Right for feeds, galleries and anything the reader is grazing rather than searching. Cases with Infinite Scroll by tommyjepsen is the loading pattern, and Infinite Drag + Scroll Gallery by Rylen Lobo is the draggable canvas version.
Three obligations come with it, and the third is the one that gets skipped.
The footer becomes unreachable. Anything below the list - contact, legal, help - moves away faster than the reader can reach it. Either the footer moves out of the scrolling container, or infinite scroll is the wrong choice for that page.
Position has to survive navigation. A reader who scrolls through 200 items, opens one and presses back should return to item 200, not to the top. That means storing the loaded pages and the scroll offset, and it is most of the work in a correct implementation.
It has to be announced. New items appearing without a sound is fine visually and invisible to a screen reader. A live region saying "20 more results loaded" is the minimum, and a real "Load more" button is better than a scroll trigger for exactly this reason.
The middle option, which is usually right
A "Load more" button. It appends like infinite scroll, so the reader never loses their place, and it keeps the footer reachable and gives keyboard and screen reader users a real control. Pair it with URL-backed pagination underneath, so page two still has an address.
That combination - append for people, paginate for machines - is what large catalogues converge on, and it is the answer for almost every listing that is neither a social feed nor a spreadsheet.
The marquee, which is a different thing
Infinite Slider by ibelick, argent-loop-infinite-slider by Hardik Kashiyani and Infinite Ribbon by edwinvakayil use the word "infinite" for a loop rather than for loading. Worth separating when searching: that family is covered in the carousel guide, and it has none of the obligations above.




Where the performance goes
Both approaches die the same way: too many nodes. A list of 5,000 rows in the DOM is slow to scroll regardless of how they got there.
Past roughly a few hundred rows, virtualise. TanStack Virtual and its relatives render only what is visible, which keeps the node count flat no matter how much has loaded. The cost is that Ctrl+F no longer finds anything offscreen, which is another argument for pagination on anything searchable.
Where else to look
The honest list, because the answer is not always us:
| Source | Best for | Trade-off |
|---|---|---|
| shadcn/ui Pagination | The control, wired and accessible | The state and the URL are yours |
| TanStack Query | Infinite queries, caching and restoring position | Not a UI |
| TanStack Virtual | Keeping a long list fast | Breaks find-in-page |
| 21st | Finished paginators, infinite lists and loop sliders | Quality varies by author, so preview before you take it |
Taking one
Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:
That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue. The 21st MCP covers the same ground without leaving the editor: ask Claude, Cursor or Codex for a paginator, get the previews inline, and let the agent write the file.
Browse pagination components →
Frequently asked
- Is infinite scroll bad for SEO?
- It is bad when it replaces addressable pages. A crawler that cannot reach page two sees only the first batch, which is how large catalogues end up with most of their inventory unreachable. The fix is not to abandon infinite scroll but to back it with real paginated URLs, so people append and machines paginate.
- When should a listing use pagination?
- Whenever the reader searches, sorts, or comes back to it. Numbered pages give you an address to link and return to, a total that answers how much there is, and a stable position for a row someone has learned. Feeds and galleries, where the reader is grazing rather than looking, are the case for appending.
- What does infinite scroll oblige you to build?
- Three things. A footer that stays reachable, or a different pattern for that page. Scroll position that survives opening an item and pressing back, which is most of the work in a correct implementation. And an announcement, because items appearing silently are invisible to a screen reader; a real Load more button solves that better than a scroll trigger.
- How many rows before a list needs virtualising?
- Roughly a few hundred. Past that the node count itself makes scrolling slow, regardless of how the rows arrived. Virtualising keeps the count flat, at the cost of breaking find-in-page for anything offscreen, which is another argument for pagination on searchable content.