Pagination
Pagination aids user movement across an ordered collection of items that has been split into pages.
- We provide infinite scrolling guidelines, as an acceptable alternative for some usecases.
- Our pagination pattern shows a variable number of pages to accommodate mobile and desktop experiences.
- This pattern is available via your brands Figma library and our o3-button npm package.
Standard Pagination
Anatomy
- Navigation (1, 5): Previous and next buttons to navigate relatively from the currently selected page.
- Page (2,3): Numbers that indicate pages.
- Truncation (4): Indicated by ellipses (…) to replace any skipped pages.
Usage Guidelines
Pagination should be used when:
- A list has a significant number of items, typically more than 25.
- When showing all the content on a single page makes the page take too long to load.
It must:
- Be placed at the bottom of a long list that has been split up into pages.
- Navigate to the previous and next set of items in the paged list.
- Indicate when users are at the first or the last page by disabling the arrows.
<ButtonPagination currentPageOnly={false} previousPager={{ label: "previous", href: "#previous" }} nextPager={{ label: "next", href: "#next" }} pages={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((p) => ({ href: `#${p}`, current: p === 5, number: p, }))}/>;
<div class="o3-button-pagination"> <a href="#previous" class="o3-button o3-button--secondary o3-button-icon o3-button-icon--chevron-left o3-button-icon--icon-only o3-apply-focus-rings" > <span class="o3-button-icon__label">previous</span> </a> <a href="#1" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 1 </a> <span data-o3-button-show-when="wide" class="o3-button-pagination__ellipsis"> ... </span> <a href="#4" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 4 </a> <a href="#5" class="o3-button o3-button--secondary o3-apply-focus-rings" aria-current="page" data-o3-button-show-when="wide" > 5 </a> <a href="#6" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 6 </a> <span data-o3-button-show-when="wide" class="o3-button-pagination__ellipsis"> ... </span> <a href="#10" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 10 </a> <a href="#1" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="narrow" > 1 </a> <span data-o3-button-show-when="narrow" class="o3-button-pagination__ellipsis" > ... </span> <a href="#5" class="o3-button o3-button--secondary o3-apply-focus-rings" aria-current="page" data-o3-button-show-when="narrow" > 5 </a> <span data-o3-button-show-when="narrow" class="o3-button-pagination__ellipsis" > ... </span> <a href="#10" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="narrow" > 10 </a> <a href="#next" class="o3-button o3-button--secondary o3-button-icon o3-button-icon--chevron-right o3-button-icon--icon-only o3-apply-focus-rings" > <span class="o3-button-icon__label">next</span> </a></div>
Current page only
Show the current page only when jumping quickly to the beginning or end of results does not enhance the user experience.
Contextual pages
For enhanced navigation of pages, including the ability to jump to the first and last page, use the following pattern:
When all pages can be displayed
Our pagination pattern supports 4 pages on small viewports, such as mobile devices, and 7 pages on larger desktop viewports. When there are more than 7 pages, we hide pages behind an ellipsis.
When the selected page is one of the first 2 pages
Show the first 3 pages; ellipsis; and the last 1 or 3 pages, as space allows.
When the selected page is one of the last 2 pages
Show the first page, or first 3 where space allows; ellipsis; and the last 3 pages.
When the 3rd page is selected
Show the first 3 pages, or 4 pages where space allows; the ellipsis; and 1 or 2 more pages, as space allows.
When the selected page is the 3rd from the last page
Show the first page, or first 2 pages where space allows; the ellipsis; and 3 or 4 last pages, as space allows.
When the selected page is over 3 from the first and last page
Show the first page; ellipsis; the selected page, with 1 page either side if space allows; another ellipsis; and the last page.
Themes
Our pagination pattern supports all button themes. For example:
Standard Theme
<ButtonPagination currentPageOnly={false} previousPager={{ label: "previous", href: "#previous" }} nextPager={{ label: "next", href: "#next" }} pages={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((p) => ({ href: `#${p}`, current: p === 5, number: p, }))}/>;
<div class="o3-button-pagination"> <a href="#previous" class="o3-button o3-button--secondary o3-button-icon o3-button-icon--chevron-left o3-button-icon--icon-only o3-apply-focus-rings" > <span class="o3-button-icon__label">previous</span> </a> <a href="#1" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 1 </a> <span data-o3-button-show-when="wide" class="o3-button-pagination__ellipsis"> ... </span> <a href="#4" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 4 </a> <a href="#5" class="o3-button o3-button--secondary o3-apply-focus-rings" aria-current="page" data-o3-button-show-when="wide" > 5 </a> <a href="#6" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 6 </a> <span data-o3-button-show-when="wide" class="o3-button-pagination__ellipsis"> ... </span> <a href="#10" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" > 10 </a> <a href="#1" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="narrow" > 1 </a> <span data-o3-button-show-when="narrow" class="o3-button-pagination__ellipsis" > ... </span> <a href="#5" class="o3-button o3-button--secondary o3-apply-focus-rings" aria-current="page" data-o3-button-show-when="narrow" > 5 </a> <span data-o3-button-show-when="narrow" class="o3-button-pagination__ellipsis" > ... </span> <a href="#10" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="narrow" > 10 </a> <a href="#next" class="o3-button o3-button--secondary o3-button-icon o3-button-icon--chevron-right o3-button-icon--icon-only o3-apply-focus-rings" > <span class="o3-button-icon__label">next</span> </a></div>
Inverse Theme
<ButtonPagination currentPageOnly={false} previousPager={{ label: "previous", href: "#previous" }} nextPager={{ label: "next", href: "#next" }} pages={[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((p) => ({ href: `#${p}`, current: p === 5, number: p, }))} theme="inverse"/>;
<div class="o3-button-pagination"> <a href="#previous" class="o3-button o3-button--secondary o3-button-icon o3-button-icon--chevron-left o3-button-icon--icon-only o3-apply-focus-rings" data-o3-theme="inverse" > <span class="o3-button-icon__label">previous</span> </a> <a href="#1" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" data-o3-theme="inverse" > 1 </a> <span data-o3-button-show-when="wide" class="o3-button-pagination__ellipsis o3-button-pagination__ellipsis--inverse" > ... </span> <a href="#4" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" data-o3-theme="inverse" > 4 </a> <a href="#5" class="o3-button o3-button--secondary o3-apply-focus-rings" aria-current="page" data-o3-button-show-when="wide" data-o3-theme="inverse" > 5 </a> <a href="#6" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" data-o3-theme="inverse" > 6 </a> <span data-o3-button-show-when="wide" class="o3-button-pagination__ellipsis o3-button-pagination__ellipsis--inverse" > ... </span> <a href="#10" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="wide" data-o3-theme="inverse" > 10 </a> <a href="#1" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="narrow" data-o3-theme="inverse" > 1 </a> <span data-o3-button-show-when="narrow" class="o3-button-pagination__ellipsis o3-button-pagination__ellipsis--inverse" > ... </span> <a href="#5" class="o3-button o3-button--secondary o3-apply-focus-rings" aria-current="page" data-o3-button-show-when="narrow" data-o3-theme="inverse" > 5 </a> <span data-o3-button-show-when="narrow" class="o3-button-pagination__ellipsis o3-button-pagination__ellipsis--inverse" > ... </span> <a href="#10" class="o3-button o3-button--secondary o3-apply-focus-rings" data-o3-button-show-when="narrow" data-o3-theme="inverse" > 10 </a> <a href="#next" class="o3-button o3-button--secondary o3-button-icon o3-button-icon--chevron-right o3-button-icon--icon-only o3-apply-focus-rings" data-o3-theme="inverse" > <span class="o3-button-icon__label">next</span> </a></div>
Infinite scroll
There are some cases when infinite scroll is appropriate. This is a common pattern within our iOS and Android apps. Origami does not currently provide a full pattern for this, however we recommend the following:
- Where infinite scrolling is used, start loading items when merchants are close to the bottom, roughly 5 items from the end.
- Show our legacy loading indicator below the list to indicate that items have been requested.
- After more results have been fetched, they should load in below.
- You’re working on a native application, with an established pattern.
- You’re working on the web, where it is not an established pattern for us, unless user research shows they improve your interface. - It interferes with access to content below, such as our footer. - Where returning to or sharing a given pages is helpful.