Pagination
Navigate through pages of content with dots, numbers, or page controls.
Page numbers
Section titled “Page numbers”Navigate through paginated data with numbered buttons and prev/next arrows. Use usePagination to generate the page list.
Show code
import { type PaginationItem, usePagination } from '@volvo-cars/react-headless';import { Icon, IconButton } from '@volvo-cars/react-icons';
export function PagePagination() { const { setPage, pages, previousButtonProps, nextButtonProps } = usePagination({ totalPages: 10, initialPage: 5 });
return ( <nav aria-label="pagination" className="flex-row gap-8"> <ul style={{ display: 'contents', listStyle: 'none' }}> <li> <IconButton {...previousButtonProps} icon="chevron-back" aria-label="Go to previous page" variant="clear" /> </li> {pages.map((page: PaginationItem) => { if (page.type === 'ELLIPSIS') { return ( <li key={page.type} className="w-40 flex-row items-end justify-center" > <Icon icon="three-dots" size={16} alt="Hidden pages" /> </li> ); } if (page.type === 'ELLIPSIS_SMALL') { return ( <li key={page.type} className="w-40 flex-row items-end justify-center lg:hidden" > <Icon icon="three-dots" size={16} alt="Hidden pages" /> </li> ); } const pageNumber = page.value; if (pageNumber === undefined) return null; return ( <li key={pageNumber} className={page.isAdditional ? 'until-lg:hidden' : ''} > <button type="button" aria-label={`Go to page ${pageNumber}`} aria-current={page.isActive ? 'page' : undefined} className="icon-button-clear current:bg-surface-neutral current:text-inverted" onClick={() => setPage(pageNumber)} > {pageNumber} </button> </li> ); })} <li> <IconButton {...nextButtonProps} icon="chevron-forward" aria-label="Go to next page" variant="clear" /> </li> </ul> </nav> );}Use dots for carousels where each dot represents a single visible item. Best for 5 or fewer items.
Show code
<ul class="pagination-dots"> <li> <button type="button" aria-current="true"> <span class="sr-only">Go to slide 1</span> </button> </li> <li> <button type="button"> <span class="sr-only">Go to slide 2</span> </button> </li> <li> <button type="button"> <span class="sr-only">Go to slide 3</span> </button> </li> <li> <button type="button"> <span class="sr-only">Go to slide 4</span> </button> </li> <li> <button type="button"> <span class="sr-only">Go to slide 5</span> </button> </li></ul>Apply the pagination-dots class to a container of buttons. Mark the active dot with aria-current="true".
<div class="pagination-dots"> <button aria-current="true"><span class="sr-only">Slide 1</span></button> <button><span class="sr-only">Slide 2</span></button> <button><span class="sr-only">Slide 3</span></button></div>With scroll-snap carousel
Section titled “With scroll-snap carousel”Combine with useSnapIndicators and useSnapNavigation for a complete carousel.
Numeric position
Section titled “Numeric position”Display position as text (e.g., “3 / 10”) for slideshows or galleries where the total count matters.
Use activeIndex from useSnapIndicators to show the current position and indicators.length for the total.
With filled pill overlay
Section titled “With filled pill overlay”Combine pagination dots with an absolute-positioned pill-filled overlay showing the numeric position.
Accessibility
Section titled “Accessibility”- Container label: add
aria-label="Pagination"to the<nav>wrapper - Active indicator: use
aria-current="page"(page numbers) oraria-current="true"(dots) - Button labels: provide descriptive text, e.g.,
aria-label="Go to page 5"or usesr-onlyspans for dots - Keyboard: ensure Tab navigates between buttons and Enter/Space activates them
usePagination. Generates page lists with ellipsis for numbered paginationuseSnapIndicators. Returns indicator state for scroll-snap carouselsuseSnapNavigation. Returns prev/next button props for scroll-snap containers