Jump to a component
Core · Navigation
Pagination
Pagination reads a long list a page at a time: what this page holds, then previous, the page numbers and next. A list of one page shows none.
Live, from @anicanon/sakuga 2.0.0
Sakuga for iOS and Android is coming
iOS
Coming soon
Pagination for iOS is in the roughs. The tokens it will read are the ones on this page, the same on every platform.
Android
Coming soon
Pagination for Android is in the roughs. The tokens it will read are the ones on this page, the same on every platform.
- Use it for
- Reading a long list a page at a time, under the list it pages: productions at 24 a page, counted as "1–24 of 31 shorts".
- Not for
- Where a person is in a flow they step throughStepper
- A shelf that leads to everything on itSectionHeader
- The pages of a manga issue in the editorIssueStrip
Guidelines
- Pass
page,pagesand, when the total is known,total,pageSizeandnoun: the count reads "1–24 of 31 shorts". - Every number carries the page language's thousands separator (
<html lang>, English when it has none): "1–25 of 2,481 people", and "2.481" on a Portuguese page. The page numbers do too, spoken and shown. - Lists of productions page at 24, as the product's clips list does; search and filters sit above the list and send you back to page 1.
- Far pages fold into an ellipsis around the current one: 1 … 4 5 6 … 12.
hrefsgives each page an address; without it the pages are buttons that callonChangewith the page.- The current page's fill slides to the new page on
motion-base; numbers sink on press. - With sound on, going to another page plays the choose sound, from a number or an arrow (README · Sound).
- Put it under the list it pages, across the list's full width. One per list.
- Sliding across the page numbers moves the pill with the pointer; let go on a number to go to that page.
import { useState } from 'react';
import { Pagination } from '@anicanon/sakuga/ui';
export default function PaginationExample() {
const [page, setPage] = useState(1);
const [page2, setPage2] = useState(5);
return (
<>
<Pagination
page={page}
pages={2}
total={31}
pageSize={24}
noun="shorts"
label="Pages of shorts"
onChange={setPage}
/>
<Pagination
page={page2}
pages={12}
total={281}
pageSize={24}
noun="pictures"
label="Pages of pictures"
onChange={setPage2}
/>
</>
);
}PropsPaginationProps
pagerequirednumberpagesrequirednumbertotalnumberpageSizenumbernounstringlabelstringDefault 'Pages'hrefsstring[]onChange(page: number) => voidclassNamestringEach token reads a role, and the role lands on a value in each theme. Change the role and every component that reads it follows.
Space and shape
pagination-gapgap-xlpagination-padding-topinset-lgpagination-edge-top-widthpagination-nav-gapgap-2xspagination-nav-icon-button-disabled-opacityopacity-disabledpagination-n-min-widthpagination-n-heightpagination-n-padding-xinset-smpagination-n-radiusradius-fullpagination-n-active-scalescale-press-smpagination-gap-min-widthpagination-nav-glide-radiusradius-fullType
pagination-count-fonttext-captionpagination-n-fonttext-labelpagination-gap-fonttext-labelMotion
pagination-n-durationmotion-fastpagination-n-easingease-standardpagination-n-active-durationmotion-instantChecked automatically with axe-core 4.11.4 against WCAG 2.2 A and AA, on the live preview above, in light and dark, on 26 October 2026.
- Result
- No issues found, in light or in dark.
- By design
- A navigation region named by
label(default "Pages"): the count reads as text, then Tab moves through "Previous page", each "Page 3" (the current one marked "current page") and "Next page", which are disabled at the ends: an arrow that turns off under focus hands focus to the current page. The ellipsis is hidden. Sliding is for the pointer; each page is still its own link or button. - Not tested
- The automated check doesn't test keyboard use, focus order or what a screen reader says. The lines above are the design system's own account of them.