Back to Learn Hub
Comprehensive Guide

Accessible Pagination Patterns

Every pattern from classic page numbers to infinite scroll

Classic Numbered Pagination

The most common pagination pattern. The key ingredients: wrap in a <nav> landmark, use proper list structure, and indicate the current page with aria-current.

<nav> Landmark

Wrapping pagination in <nav aria-label="Pagination"> creates a landmark that screen reader users can jump to directly.

aria-current='page'

This attribute tells screen readers which page is currently active. Without it, users only know visually which page is selected.

Descriptive Labels

Use aria-label="Go to page 3" on buttons. Generic "3" labels don't explain what the button does.

Try It Yourself

Problem: No landmark, no list structure, no aria-current!
1
2
3
...
10

❌ VoiceOver: "1, 2, 3, 10" — no context that these are page numbers!

Don't: Divs with Click Handlers

<!-- ❌ INACCESSIBLE -->
<div class="pagination">
  <div onclick="prevPage()">‹</div>
  <div onclick="goToPage(1)" class="active">1</div>
  <div onclick="goToPage(2)">2</div>
  <div onclick="goToPage(3)">3</div>
  <div onclick="nextPage()">›</div>
</div>

<!-- Problems:
- No keyboard access (divs aren't focusable)
- No landmark for navigation
- No indication of current page
- Screen reader can't understand structure -->

Do: Semantic Navigation

<!-- ✅ ACCESSIBLE -->
<nav aria-label="Pagination">
  <ul>
    <li>
      <button aria-label="Previous page">‹</button>
    </li>
    <li>
      <button aria-current="page" aria-label="Page 1, current">
        1
      </button>
    </li>
    <li>
      <button aria-label="Go to page 2">2</button>
    </li>
    <li>
      <button aria-label="Next page">›</button>
    </li>
  </ul>
</nav>
Announce Page Changes in SPAs
In single-page applications, the page doesn't reload when changing pages. Use a live region to announce "Page 3 of 10" or update the document title to include the current page number.
Ellipsis is Decorative
The "..." (ellipsis) between page numbers is purely visual. Add aria-hidden="true" to hide it from screen readers—it adds no useful information.

Understanding the Pagination Pattern

Pagination splits a long list into pages and gives the user a way to move between them: numbered links, Previous and Next, a Load More button, or automatic loading as the user scrolls. The controls are simple. The accessibility work is in three things the controls do not show on their own: telling the user where they are, telling them what changed, and putting keyboard focus somewhere sensible afterwards.

The demo above builds numbered pagination as a <nav>landmark named "Pagination" containing a list of buttons, marks the current page with aria-current="page", gives every control a full name such as "Go to page 3", hides the decorative ellipsis, and announces "Page 3 of 10" through a live region. The Load More section shows the other half of the pattern: after new items arrive, focus moves to the first of them so a keyboard user lands on the new content instead of at the button they just pressed.

WCAG 2.2 Success Criteria Involved

Success criterionLevelWhat it requires here
1.3.1 Info and RelationshipsAA named navigation landmark and a real list expose the structure that the visual row of numbers implies.
2.4.4 Link Purpose (In Context)AEach control's name says what it does: 'Go to page 3', 'Previous page', not a bare number or an arrow glyph.
1.4.1 Use of ColorAThe current page is identified by aria-current and a visual cue beyond colour, such as weight or a border.
4.1.3 Status MessagesAAWhen the page changes without a reload, or more items load, the change is announced through a live region because focus did not move to it.
2.4.3 Focus OrderAAfter Load More, focus moves to the first new item; after a page change, it stays on the control or moves to the results heading.
2.5.8 Target Size (Minimum)AAPage-number targets packed tightly together need 24 by 24 CSS pixels each, or spacing that keeps 24 pixel circles from overlapping.
2.4.1 Bypass BlocksAThe landmark lets screen reader users jump straight to the pagination instead of reading through every result.
3.2.3 Consistent NavigationAAThe same pagination control appears in the same place on every listing page across the site.

Expected Keyboard Interaction

Keyboard interaction for pagination controls
KeyExpected result
TabMoves through Previous, each visible page number, and Next in reading order. Disabled Previous and Next remain in the page but are skipped.
Shift + TabMoves backwards through the same controls.
EnterFollows a page link, or activates a page button, and triggers the page-change announcement.
SpaceActivates a page control built as a button; links do not respond to Space.
Enter or Space on Load MoreLoads the next batch, announces the count, and moves focus to the first new item.

The Failures We See Most Often

  1. Divs and spans with click handlers. The numbers look like links but are not focusable, have no role, and cannot be activated from the keyboard. Use anchors when a page has a URL and buttons when it does not.
  2. Current page shown by colour only. A filled background and nothing else. Without aria-current a screen reader hears a list of identical numbers, and a user who cannot distinguish the colour sees the same.
  3. Silent updates. In a single-page app the results swap with no announcement, or infinite scroll keeps loading without telling anyone, and the footer becomes unreachable. Announce the change, and offer a Load More or View All alternative to endless scrolling.

The accessible pagination guide covers the choice between links and buttons, URL and title updates for each page, how to handle very long page ranges, and the trade offs between numbered pages, Load More, and infinite scroll for different kinds of content.