</>
Skip to content
CSS lessons (59/66)

CSS — Pagination

The markup

Pagination is another list of links:

<nav aria-label="Pagination">
    <ul class="pagination">
        <li><a href="?page=1" aria-label="Previous">‹</a></li>
        <li><a href="?page=1">1</a></li>
        <li><a href="?page=2" class="active" aria-current="page">2</a></li>
        <li><a href="?page=3">3</a></li>
        <li><span class="ellipsis">…</span></li>
        <li><a href="?page=12">12</a></li>
        <li><a href="?page=3" aria-label="Next">›</a></li>
    </ul>
</nav>

Two accessibility signals: aria-current="page" marks where the user is; aria-label explains arrow-only buttons.

The styling

.pagination {
    display: flex;
    gap: 4px;
    list-style: none;
    padding: 0;
    justify-content: center;
}

.pagination a,
.pagination span {
    display: flex;                 /* perfect centering   */
    align-items: center;
    justify-content: center;
    min-width: 40px;               /* touch-target friendly */
    height: 40px;
    padding: 0 8px;
    border-radius: 8px;
    text-decoration: none;
    color: #334155;
    transition: background .15s;
}

.pagination a:hover { background: #f0fdfa; color: #0d9488; }

.pagination .active {
    background: #0d9488;
    color: white;
    pointer-events: none;          /* current page isn't clickable */
}

.pagination .disabled {
    opacity: .4;
    pointer-events: none;
}

.ellipsis {
    color: #94a3b8;
}

(Row of 40px rounded squares; teal pill on the current page; dimmed edges at boundaries.)

Edge states — prev/next disabling

On page 1, Previous shouldn't pretend to work:

<li><span class="disabled" aria-disabled="true">‹</span></li>

Swap <a> for a non-interactive span (or omit the link) when there's nowhere to go.

Smart number truncation

Ten pages fit; a hundred don't. Show a window around the current page:

function pageList(current, total) {
    const pages = new Set([1, total, current - 1, current, current + 1]);
    // always keep 2 near the edges
    if (current <= 3) [2, 3, 4].forEach(p => p < total && pages.add(p));
    if (current >= total - 2) [total-1, total-2, total-3].forEach(p => p > 1 && pages.add(p));

    return [...pages].sort((a,b) => a-b);
}
// pageList(6, 40) → [1, 5, 6, 7, 40] → render "… 5 6 7 …"

Insert .ellipsis spans wherever numbers jump by more than one.

Variants

Load-more button (often better UX)

.load-more {
    display: block;
    margin: 24px auto;
    padding: 12px 32px;
}

Infinite scroll and load-more beat numbered pagination for feeds; keep numbered pagination for search results where users want to jump/judge depth.

Compact prev/next only

.pager {
    display: flex;
    justify-content: space-between;
}

Blog-post style: "← Older | Newer →". Zero math needed.

Server-side note

Links (?page=2) stay crawlable and work without JS — pagination is one place plain links genuinely beat click handlers.

Mini Practice

  1. Base pagination with all four state styles.
  2. Disable prev on page 1, next on last page.
  3. Implement pageList(); render windowed numbers with ellipses.
  4. Add keyboard focus-visible rings matching hover.
  5. Build the blog-style prev/next pager variant.

Next: multiple columns →

Related Topics

Frequently Asked Questions about Pagination

What is Pagination in CSS?

Pagination is a fundamental concept in CSS. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Pagination?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Pagination.

Why is Pagination important in CSS?

Pagination is essential for CSS development. Understanding this concept will help you write better code and solve real-world problems more effectively.