Pagination
Pagination is a fully CSS-driven navigation component for splitting content across multiple pages. It requires no JavaScript — all states and variants are controlled with declarative HTML classes.
Use Pagination for:
- Data tables and search results
- Blog post and article listings
- File browsers and media galleries
- Any content split across multiple pages
Getting Started
Apply .pagination to a <ul> element. Each page button is a <li class="page-item"> containing an <a class="page-link">.
<ul class="pagination">
<li className="page-item">
<a href="#" className="page-link page-prev"></a>
</li>
<li className="page-item">
<a href="#" className="page-link">1</a>
</li>
<li className="page-item is-active">
<a href="#" className="page-link">2</a>
</li>
<li className="page-item">
<a href="#" className="page-link">3</a></li>
<li className="page-item is-disabled">
<a href="#" className="page-link">…</a>
</li>
<li className="page-item">
<a href="#" className="page-link">10</a>
</li>
<li className="page-item">
<a href="#" className="page-link page-next"></a>
</li>
</ul>
Structure
| Element | Class / Attribute | Purpose |
|---|---|---|
| Container | pagination | Root class. Apply to <ul>. Accepts layout and size modifiers. |
| Item wrapper | page-item | Each <li> wrapper for a page button. Accepts state classes. |
| Link | page-link | The clickable <a> inside each item. Carries all visual styling. |
| Previous button | page-prev | Added to the prev <a>. Injects a left chevron icon via CSS ::before. |
| Next button | page-next | Added to the next <a>. Injects a right chevron icon via CSS ::after. |
Item States
State modifiers are applied to individual .page-item elements.
| Modifier | Applies to | Effect |
|---|---|---|
is-active | page-item | Marks the current page. Background fills with --accent, text becomes --accent-contrast, cursor becomes default. |
is-disabled | page-item | Makes the item non-interactive. Applies pointer-events: none and muted text color via --muted. |
is-active
Highlights the current page. The background fills with --accent and text color switches to --accent-contrast.
<ul class="pagination">
<li class="page-item is-disabled">
<a href="#" class="page-link page-prev" aria-disabled="true">Prev</a>
</li>
<li class="page-item is-active">
<a href="#" class="page-link">1</a>
</li>
<li class="page-item">
<a href="#" class="page-link">2</a>
</li>
<li class="page-item">
<a href="#" class="page-link">3</a>
</li>
<li class="page-item">
<a href="#" class="page-link page-next">Next</a>
</li>
</ul>
is-disabled
Makes the item non-interactive via pointer-events: none and renders text in --muted.
For full accessibility, also add aria-disabled="true" to the inner <a> element.
<ul class="pagination">
<li class="page-item">
<a href="#" class="page-link page-prev">Prev</a>
</li>
<li class="page-item">
<a href="#" class="page-link">1</a>
</li>
<li class="page-item is-disabled">
<a href="#" class="page-link" aria-disabled="true">…</a>
</li>
<li class="page-item">
<a href="#" class="page-link">9</a>
</li>
<li class="page-item">
<a href="#" class="page-link page-next">Next</a>
</li>
</ul>
is-disabledblocks mouse and hover events at the CSS level. Always pair witharia-disabled="true"on the<a>element for keyboard and screen reader accessibility.
Layout Modes
| Modifier | Effect |
|---|---|
| default (separated) | Each item is an individual rounded button with a 0.25rem gap. All corners of .page-link receive --radius-1. |
is-grouped | Items join into a single continuous bar with no gaps. Only the first and last items have outer rounded corners, via CSS logical properties for RTL compatibility. |
Separated (Default)
Each page item is an individual button separated by a 0.25rem gap. All four corners of .page-link receive border-radius via --radius-1.
is-grouped
Items join into a single continuous bar with no gaps. The first item gets start-side rounded corners and the last gets end-side rounded corners — using CSS logical properties (border-start-start-radius, border-end-end-radius) for full RTL support.
<ul class="pagination is-grouped">
<li class="page-item"><a href="#" class="page-link page-prev">Prev</a></li>
<li class="page-item"><a href="#" class="page-link">1</a></li>
<li class="page-item is-active"><a href="#" class="page-link">2</a></li>
<li class="page-item"><a href="#" class="page-link">3</a></li>
<li class="page-item"><a href="#" class="page-link page-next">Next</a></li>
</ul>
Prev & Next Chevron Icons
The previous and next chevron icons are rendered entirely via CSS ::before and ::after pseudo-elements using mask-image. No icon font, inline SVG, or extra markup is required — add .page-prev or .page-next to the <li>.
<ul class="pagination">
<li class="page-item">
<a href="#" class="page-link page-prev">Prev</a>
</li>
<li class="page-item">
<a href="#" class="page-link page-next">Next</a>
</li>
</ul>
The chevron color always matches currentColor, so it adapts automatically to hover, active, and disabled states without extra CSS.
RTL Support
In right-to-left layouts both chevrons are automatically mirrored via scaleX(-1) using the :dir(rtl) CSS pseudo-class. No extra classes or overrides are needed.
<ul class="pagination" dir="rtl">
<li class="page-item"><a href="#" class="page-link page-prev">السابق</a></li>
<li class="page-item is-active"><a href="#" class="page-link">١</a></li>
<li class="page-item"><a href="#" class="page-link">٢</a></li>
<li class="page-item"><a href="#" class="page-link page-next">التالي</a></li>
</ul>
Size Variants
Size modifiers are applied to the .pagination container and scale all items uniformly.
| Class | Item Height | Min Width | Font Size |
|---|---|---|---|
| default | 2.5rem | 2.5rem | 1rem |
is-small | 2rem | 2rem | 0.875rem |
is-large | 3rem | 3rem | 1.25rem |
<!-- Small -->
<ul class="pagination is-small">
<li class="page-item"><a href="#" class="page-link page-prev">Prev</a></li>
<li class="page-item is-active"><a href="#" class="page-link">1</a></li>
<li class="page-item"><a href="#" class="page-link">2</a></li>
<li class="page-item"><a href="#" class="page-link page-next">Next</a></li>
</ul>
<!-- Large -->
<ul class="pagination is-large">
<li class="page-item"><a href="#" class="page-link page-prev">Prev</a></li>
<li class="page-item is-active"><a href="#" class="page-link">1</a></li>
<li class="page-item"><a href="#" class="page-link">2</a></li>
<li class="page-item"><a href="#" class="page-link page-next">Next</a></li>
</ul>
Accessibility
- Use
<ul>as the container and wrap the whole component in<nav aria-label="Pagination">for landmark navigation. - Add
aria-current="page"to the active<a>element alongsideis-active. - Add
aria-disabled="true"to the<a>inside every.is-disableditem — CSSpointer-events: nonealone does not prevent keyboard focus. - Focus rings are rendered via
outlineandbox-shadowusing--accentand do not affect layout.
Notes
- Pagination requires no JavaScript — all states are controlled via HTML classes.
- The link class is
page-link, notnav-link— use.page-item .page-linkin all markup. - Active state uses
--accentand--accent-contrast, not--primaryand--body-bg. - Disabled state text color comes from
--muted, not--text-muted. is-disabledon a.page-itemis also the correct way to render a non-interactive ellipsis separator.- Chevron icons use
currentColorviamask-image— they automatically adapt to all states. - RTL chevron mirroring is automatic via
:dir(rtl)and requires no extra classes. - Size modifiers apply to the
.paginationcontainer, not individual.page-itemelements. is-groupedand size modifiers can be combined:pagination is-grouped is-mediumis valid.