Pagination
Pagination helps users navigate through large sets of content.
Basic Pagination
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev" aria-label="Previous">
<i class="ph ph-caret-left"></i>
</a>
<a href="#" class="Pagination-item">1</a>
<a href="#" class="Pagination-item active">2</a>
<a href="#" class="Pagination-item">3</a>
<a href="#" class="Pagination-item">4</a>
<a href="#" class="Pagination-item">5</a>
<a href="#" class="Pagination-item Pagination-item--next" aria-label="Next">
<i class="ph ph-caret-right"></i>
</a>
</nav>
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev">
<i class="ph ph-caret-left"></i>
</a>
<a href="#" class="Pagination-item">1</a>
<a href="#" class="Pagination-item active">2</a>
<a href="#" class="Pagination-item">3</a>
<a href="#" class="Pagination-item Pagination-item--next">
<i class="ph ph-caret-right"></i>
</a>
</nav>
With Ellipsis
For large page counts, use ellipsis to indicate skipped pages.
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev">
<i class="ph ph-caret-left"></i>
</a>
<a href="#" class="Pagination-item">1</a>
<span class="Pagination-ellipsis">...</span>
<a href="#" class="Pagination-item">4</a>
<a href="#" class="Pagination-item active">5</a>
<a href="#" class="Pagination-item">6</a>
<span class="Pagination-ellipsis">...</span>
<a href="#" class="Pagination-item">20</a>
<a href="#" class="Pagination-item Pagination-item--next">
<i class="ph ph-caret-right"></i>
</a>
</nav>
<span class="Pagination-ellipsis">...</span>
Disabled States
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev disabled" aria-disabled="true">
<i class="ph ph-caret-left"></i>
</a>
<a href="#" class="Pagination-item active">1</a>
<a href="#" class="Pagination-item">2</a>
<a href="#" class="Pagination-item">3</a>
<a href="#" class="Pagination-item Pagination-item--next">
<i class="ph ph-caret-right"></i>
</a>
</nav>
<a class="Pagination-item Pagination-item--prev disabled" aria-disabled="true">
Compact
For tight spaces, use the compact variant.
<nav class="Pagination Pagination--compact">
<a href="#" class="Pagination-item Pagination-item--prev">
<i class="ph ph-caret-left"></i>
</a>
<span class="Pagination-info">Page 5 of 20</span>
<a href="#" class="Pagination-item Pagination-item--next">
<i class="ph ph-caret-right"></i>
</a>
</nav>
<nav class="Pagination Pagination--compact">
<a href="#" class="Pagination-item Pagination-item--prev">...</a>
<span class="Pagination-info">Page 5 of 20</span>
<a href="#" class="Pagination-item Pagination-item--next">...</a>
</nav>
With Page Size
Show
per page
<div style="display: flex; justify-content: space-between; align-items: center; width: 100%;">
<div style="display: flex; align-items: center; gap: var(--space-2); font-size: 0.9rem; color: var(--fg-3);">
<span>Show</span>
<select class="Select" style="width: auto; padding: var(--space-1) var(--space-2);">
<option>10</option>
<option>25</option>
<option>50</option>
</select>
<span>per page</span>
</div>
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev">
<i class="ph ph-caret-left"></i>
</a>
<a href="#" class="Pagination-item active">1</a>
<a href="#" class="Pagination-item">2</a>
<a href="#" class="Pagination-item">3</a>
<a href="#" class="Pagination-item Pagination-item--next">
<i class="ph ph-caret-right"></i>
</a>
</nav>
</div>
Common Patterns
Data Table Footer
<div style="width: 100%; border: 1px solid var(--bd); border-radius: var(--r-m); overflow: hidden;">
<div style="padding: var(--space-3); background: var(--bg-s); border-bottom: 1px solid var(--bd); font-weight: 600; font-size: 0.9rem;">Recent Orders</div>
<div style="padding: var(--space-3); border-bottom: 1px solid var(--bd); font-size: 0.9rem;">Order #1042 — $129.00</div>
<div style="padding: var(--space-3); border-bottom: 1px solid var(--bd); font-size: 0.9rem;">Order #1041 — $67.50</div>
<div style="padding: var(--space-3); border-bottom: 1px solid var(--bd); font-size: 0.9rem;">Order #1040 — $245.00</div>
<div style="padding: var(--space-3); display: flex; justify-content: space-between; align-items: center; background: var(--bg-s);">
<span style="font-size: 0.85rem; color: var(--fg-3);">Showing 1–3 of 128</span>
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev" aria-label="Previous"><i class="ph ph-caret-left"></i></a>
<a href="#" class="Pagination-item active">1</a>
<a href="#" class="Pagination-item">2</a>
<a href="#" class="Pagination-item">3</a>
<span class="Pagination-ellipsis">...</span>
<a href="#" class="Pagination-item">43</a>
<a href="#" class="Pagination-item Pagination-item--next" aria-label="Next"><i class="ph ph-caret-right"></i></a>
</nav>
</div>
</div>
Search Results
About 1,240 results (0.42 seconds)
Result Title
Brief description of the search result...
<div style="width: 100%; max-width: 500px;">
<div style="margin-bottom: var(--space-3); font-size: 0.9rem; color: var(--fg-3);">About 1,240 results (0.42 seconds)</div>
<div style="display: flex; flex-direction: column; gap: var(--space-3); margin-bottom: var(--space-4);">
<div style="padding: var(--space-3); border-left: 3px solid var(--accent); background: var(--bg-s);">
<div style="font-weight: 600; margin-bottom: var(--space-1);">Result Title</div>
<div style="font-size: 0.85rem; color: var(--fg-3);">Brief description of the search result...</div>
</div>
</div>
<nav class="Pagination" style="justify-content: center;">
<a href="#" class="Pagination-item Pagination-item--prev disabled" aria-disabled="true"><i class="ph ph-caret-left"></i></a>
<a href="#" class="Pagination-item active">1</a>
<a href="#" class="Pagination-item">2</a>
<a href="#" class="Pagination-item">3</a>
<span class="Pagination-ellipsis">...</span>
<a href="#" class="Pagination-item">124</a>
<a href="#" class="Pagination-item Pagination-item--next"><i class="ph ph-caret-right"></i></a>
</nav>
</div>
Card Grid with Pagination
Card 1
Card 2
Card 3
<div style="width: 100%;">
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-3); margin-bottom: var(--space-4);">
<div style="padding: var(--space-3); background: var(--bg-s); border-radius: var(--r-m); text-align: center; font-size: 0.85rem; color: var(--fg-3);">Card 1</div>
<div style="padding: var(--space-3); background: var(--bg-s); border-radius: var(--r-m); text-align: center; font-size: 0.85rem; color: var(--fg-3);">Card 2</div>
<div style="padding: var(--space-3); background: var(--bg-s); border-radius: var(--r-m); text-align: center; font-size: 0.85rem; color: var(--fg-3);">Card 3</div>
</div>
<div style="display: flex; justify-content: center;">
<nav class="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev"><i class="ph ph-caret-left"></i></a>
<a href="#" class="Pagination-item">1</a>
<a href="#" class="Pagination-item active">2</a>
<a href="#" class="Pagination-item">3</a>
<a href="#" class="Pagination-item Pagination-item--next"><i class="ph ph-caret-right"></i></a>
</nav>
</div>
</div>
Mobile Compact Pagination
<div style="max-width: 320px; width: 100%;">
<nav class="Pagination Pagination--compact" style="width: 100%; justify-content: space-between;">
<a href="#" class="Pagination-item Pagination-item--prev"><i class="ph ph-caret-left"></i></a>
<span class="Pagination-info">Page 3 of 12</span>
<a href="#" class="Pagination-item Pagination-item--next"><i class="ph ph-caret-right"></i></a>
</nav>
</div>
Customization
Override pagination styling with CSS custom properties:
/* Custom accent color */
.Pagination {
--pagination-active-bg: oklch(55% 0.2 260);
--pagination-active-fg: white;
--pagination-hover-bg: oklch(92% 0.02 260);
}
.Pagination-item.active {
background: var(--pagination-active-bg);
color: var(--pagination-active-fg);
}
.Pagination-item:hover:not(.active):not(.disabled) {
background: var(--pagination-hover-bg);
}
Rounded Items
.Pagination--rounded .Pagination-item {
border-radius: var(--r-full);
}
Bordered Variant
.Pagination--bordered .Pagination-item {
border: 1px solid var(--bd);
}
Theming
/* Dark theme overrides */
[data-theme="dark"] .Pagination-item.active {
background: oklch(70% 0.15 260);
color: oklch(15% 0 0);
}
API Reference
| Class | Description |
|---|---|
.Pagination | Container for pagination controls |
.Pagination--compact | Minimal prev/next with page info text |
.Pagination-item | Individual page link or button |
.Pagination-item--prev | Previous page button |
.Pagination-item--next | Next page button |
.Pagination-item.active | Current page indicator |
.Pagination-item.disabled | Non-interactive disabled state |
.Pagination-ellipsis | Skipped pages indicator (...) |
.Pagination-info | Page count text (compact mode) |
Attributes
| Attribute | Description |
|---|---|
aria-label | On <nav> to describe the pagination region |
aria-current="page" | On the current page item |
aria-disabled="true" | On disabled navigation items |
aria-label="Previous" | On prev/next icon-only buttons |
Structure
<nav class="Pagination" aria-label="Pagination">
<a class="Pagination-item Pagination-item--prev">...</a>
<a class="Pagination-item">1</a>
<a class="Pagination-item active" aria-current="page">2</a>
<span class="Pagination-ellipsis">...</span>
<a class="Pagination-item">10</a>
<a class="Pagination-item Pagination-item--next">...</a>
</nav>
CSS Reference
/* Base pagination */
.Pagination {
display: flex;
align-items: center;
gap: var(--space-1);
}
/* Individual page item */
.Pagination-item {
display: flex;
align-items: center;
justify-content: center;
min-width: 36px;
height: 36px;
padding: 0 var(--space-2);
font-size: 0.9rem;
font-weight: 500;
color: var(--fg);
background: transparent;
border: none;
border-radius: var(--r-s);
cursor: pointer;
text-decoration: none;
transition: background 0.15s, color 0.15s;
}
.Pagination-item:hover:not(.active):not(.disabled) {
background: var(--bg-s);
}
/* Active state */
.Pagination-item.active {
background: var(--accent);
color: white;
}
/* Disabled state */
.Pagination-item.disabled {
opacity: 0.4;
cursor: not-allowed;
pointer-events: none;
}
/* Prev/Next buttons */
.Pagination-item--prev,
.Pagination-item--next {
font-size: 1rem;
}
/* Ellipsis */
.Pagination-ellipsis {
display: flex;
align-items: center;
justify-content: center;
min-width: 36px;
height: 36px;
color: var(--fg-3);
font-size: 0.9rem;
user-select: none;
}
/* Compact variant */
.Pagination--compact {
gap: var(--space-2);
}
.Pagination-info {
font-size: 0.9rem;
color: var(--fg-3);
white-space: nowrap;
}
Accessibility
Keyboard Support
| Key | Action |
|---|---|
Tab |
Move focus between pagination items |
Enter / Space |
Activate the focused page link |
Screen Reader Guidance
Use <nav> with aria-label to create a landmark region. Mark the current page with aria-current="page" so screen readers announce it. Disabled items should use aria-disabled="true" instead of removing the href.
<nav class="Pagination" aria-label="Pagination">
<a href="#" class="Pagination-item Pagination-item--prev" aria-label="Previous page">
<i class="ph ph-caret-left"></i>
</a>
<a href="#" class="Pagination-item active" aria-current="page">2</a>
<a href="#" class="Pagination-item Pagination-item--next" aria-label="Next page">
<i class="ph ph-caret-right"></i>
</a>
</nav>
ARIA Attributes
aria-labelon<nav>to identify the pagination regionaria-current="page"on the active page elementaria-disabled="true"on non-functional prev/next when at boundariesaria-labelon icon-only buttons (Previous / Next)
Best Practices
Do
- ✓ Show current position — Always indicate which page the user is on
- ✓ Use ellipsis for large sets — Collapse middle pages to avoid overwhelming UI
- ✓ Disable boundary buttons — Gray out Previous on page 1, Next on last page
- ✓ Provide compact mode for mobile — Switch to compact pagination on small screens
- ✓ Keep first and last pages visible — Users need to know the total range
- ✓ Use semantic
<nav>element — Wrap pagination in a navigation landmark
Don’t
- ✗ Show all page numbers — Hundreds of links create visual noise
- ✗ Hide page numbers entirely — Users lose sense of position in the dataset
- ✗ Make touch targets smaller than 44px — Small targets frustrate mobile users
- ✗ Use pagination for small datasets — Under 20 items usually don’t need pagination
- ✗ Remove disabled links from DOM — Screen reader users lose navigation context
- ✗ Forget to update URL — Users expect to bookmark or share paginated views