Pagination

Links, for the same reason sortable headers are: a page of results is a URL. It can be shared, bookmarked, opened in a new tab and reached with the back button, and it works with scripting off.

Reference

sk-pagination

The current page is a <span> carrying aria-current, not a link to where you already are. Disabled ends are spans too - an anchor with no href is not focusable, and one that goes nowhere is worse than absent.

<nav class="sk-pagination" aria-label="Pagination">
  <p class="sk-pagination-info">1-20 of 240</p>
  <ul class="sk-pagination-list">
    <li><a class="sk-page sk-page-step" href="?page=1" rel="prev">…</a></li>
    <li><span class="sk-page" aria-current="page">2</span></li>
    <li><span class="sk-page-gap" aria-hidden="true">…</span></li>
    <li><a class="sk-page" href="?page=12" aria-label="Page 12">12</a></li>
  </ul>
</nav>
AttributeTypeDefaultNotes
aria-labelstring"Pagination"A page with two paginated lists needs distinct labels, or a screen reader announces two identical landmarks.
aria-current"page"-On the current page only.
data-disabled"true"-On the previous/next step when there is nowhere to go.
Around (Go)int1Pages shown either side of the current one. A gap of exactly one page renders the page rather than an ellipsis - hiding it saves nothing and costs a click to find out.

Examples

In the middle

Show markup
<nav class="sk-pagination" aria-label="Pagination">
  <p class="sk-pagination-info">
    101-120 of 240
  </p>
  <ul class="sk-pagination-list">
    <li>
      <a class="sk-page sk-page-step" href="?page=5" rel="prev">
        <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
          <path d="m15 18-6-6 6-6">
          </path>
        </svg>
        Previous
      </a>
    </li>
    <li>
      <a class="sk-page" href="?page=1" aria-label="Page 1">
        1
      </a>
    </li>
    <li>
      <span class="sk-page-gap" aria-hidden="true">
        &hellip;
      </span>
    </li>
    <li>
      <a class="sk-page" href="?page=5" aria-label="Page 5">
        5
      </a>
    </li>
    <li>
      <span class="sk-page" aria-current="page">
        6
      </span>
    </li>
    <li>
      <a class="sk-page" href="?page=7" aria-label="Page 7">
        7
      </a>
    </li>
    <li>
      <span class="sk-page-gap" aria-hidden="true">
        &hellip;
      </span>
    </li>
    <li>
      <a class="sk-page" href="?page=12" aria-label="Page 12">
        12
      </a>
    </li>
    <li>
      <a class="sk-page sk-page-step" href="?page=7" rel="next">
        Next
        <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
          <path d="m9 18 6-6-6-6">
          </path>
        </svg>
      </a>
    </li>
  </ul>
</nav>

At the ends

Previous and next become non-focusable spans rather than dead links.

Show markup
<div class="sk-flex sk-flex-col sk-gap-4">
  <nav class="sk-pagination" aria-label="Pagination">
    <p class="sk-pagination-info">
      1-20 of 240
    </p>
    <ul class="sk-pagination-list">
      <li>
        <span class="sk-page sk-page-step" data-disabled="true" aria-hidden="true">
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m15 18-6-6 6-6">
            </path>
          </svg>
          Previous
        </span>
      </li>
      <li>
        <span class="sk-page" aria-current="page">
          1
        </span>
      </li>
      <li>
        <a class="sk-page" href="?page=2" aria-label="Page 2">
          2
        </a>
      </li>
      <li>
        <span class="sk-page-gap" aria-hidden="true">
          &hellip;
        </span>
      </li>
      <li>
        <a class="sk-page" href="?page=12" aria-label="Page 12">
          12
        </a>
      </li>
      <li>
        <a class="sk-page sk-page-step" href="?page=2" rel="next">
          Next
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m9 18 6-6-6-6">
            </path>
          </svg>
        </a>
      </li>
    </ul>
  </nav>
  <nav class="sk-pagination" aria-label="Pagination">
    <p class="sk-pagination-info">
      221-240 of 240
    </p>
    <ul class="sk-pagination-list">
      <li>
        <a class="sk-page sk-page-step" href="?page=11" rel="prev">
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m15 18-6-6 6-6">
            </path>
          </svg>
          Previous
        </a>
      </li>
      <li>
        <a class="sk-page" href="?page=1" aria-label="Page 1">
          1
        </a>
      </li>
      <li>
        <span class="sk-page-gap" aria-hidden="true">
          &hellip;
        </span>
      </li>
      <li>
        <a class="sk-page" href="?page=11" aria-label="Page 11">
          11
        </a>
      </li>
      <li>
        <span class="sk-page" aria-current="page">
          12
        </span>
      </li>
      <li>
        <span class="sk-page sk-page-step" data-disabled="true" aria-hidden="true">
          Next
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m9 18 6-6-6-6">
            </path>
          </svg>
        </span>
      </li>
    </ul>
  </nav>
</div>

Short lists

Below eight pages there is nothing to elide, so nothing is.

Show markup
<div class="sk-flex sk-flex-col sk-gap-4">
  <nav class="sk-pagination" aria-label="Pagination">
    <p class="sk-pagination-info">
      21-40 of 60
    </p>
    <ul class="sk-pagination-list">
      <li>
        <a class="sk-page sk-page-step" href="?page=1" rel="prev">
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m15 18-6-6 6-6">
            </path>
          </svg>
          Previous
        </a>
      </li>
      <li>
        <a class="sk-page" href="?page=1" aria-label="Page 1">
          1
        </a>
      </li>
      <li>
        <span class="sk-page" aria-current="page">
          2
        </span>
      </li>
      <li>
        <a class="sk-page" href="?page=3" aria-label="Page 3">
          3
        </a>
      </li>
      <li>
        <a class="sk-page sk-page-step" href="?page=3" rel="next">
          Next
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m9 18 6-6-6-6">
            </path>
          </svg>
        </a>
      </li>
    </ul>
  </nav>
  <nav class="sk-pagination" aria-label="Pagination">
    <p class="sk-pagination-info">
      1-12 of 12
    </p>
    <ul class="sk-pagination-list">
      <li>
        <span class="sk-page sk-page-step" data-disabled="true" aria-hidden="true">
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m15 18-6-6 6-6">
            </path>
          </svg>
          Previous
        </span>
      </li>
      <li>
        <span class="sk-page" aria-current="page">
          1
        </span>
      </li>
      <li>
        <span class="sk-page sk-page-step" data-disabled="true" aria-hidden="true">
          Next
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m9 18 6-6-6-6">
            </path>
          </svg>
        </span>
      </li>
    </ul>
  </nav>
</div>

Wider window

Around: 2.

Show markup
<nav class="sk-pagination" aria-label="Pagination">
  <p class="sk-pagination-info">
    191-200 of 500
  </p>
  <ul class="sk-pagination-list">
    <li>
      <a class="sk-page sk-page-step" href="?page=19" rel="prev">
        <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
          <path d="m15 18-6-6 6-6">
          </path>
        </svg>
        Previous
      </a>
    </li>
    <li>
      <a class="sk-page" href="?page=1" aria-label="Page 1">
        1
      </a>
    </li>
    <li>
      <span class="sk-page-gap" aria-hidden="true">
        &hellip;
      </span>
    </li>
    <li>
      <a class="sk-page" href="?page=18" aria-label="Page 18">
        18
      </a>
    </li>
    <li>
      <a class="sk-page" href="?page=19" aria-label="Page 19">
        19
      </a>
    </li>
    <li>
      <span class="sk-page" aria-current="page">
        20
      </span>
    </li>
    <li>
      <a class="sk-page" href="?page=21" aria-label="Page 21">
        21
      </a>
    </li>
    <li>
      <a class="sk-page" href="?page=22" aria-label="Page 22">
        22
      </a>
    </li>
    <li>
      <span class="sk-page-gap" aria-hidden="true">
        &hellip;
      </span>
    </li>
    <li>
      <a class="sk-page" href="?page=50" aria-label="Page 50">
        50
      </a>
    </li>
    <li>
      <a class="sk-page sk-page-step" href="?page=21" rel="next">
        Next
        <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
          <path d="m9 18 6-6-6-6">
          </path>
        </svg>
      </a>
    </li>
  </ul>
</nav>

Under a table

Name Status Balance
Ada Lovelace ada@example.comActive1,240.00
Grace Hopper grace@example.comActive980.50
Alan Turing alan@example.comPending111.11
Katherine Johnson katherine@example.comFailed17.00
Edsger Dijkstra edsger@example.comArchived2,006.75
Show markup
<div class="sk-flex sk-flex-col sk-gap-4">
  <div class="sk-table-wrap">
    <table class="sk-table" data-density="compact" data-hoverable="true">
      <thead>
        <tr>
          <th scope="col">
            Name
          </th>
          <th scope="col">
            Status
          </th>
          <th scope="col" data-numeric="true">
            Balance
          </th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>
            <span class="sk-table-cell-stack">
              <span>
                Ada Lovelace
              </span>
              <span class="sk-table-cell-muted">
                ada@example.com
              </span>
            </span>
          </td>
          <td>
            <span class="sk-badge" data-status="success">
              Active
            </span>
          </td>
          <td data-numeric="true">
            1,240.00
          </td>
        </tr>
        <tr>
          <td>
            <span class="sk-table-cell-stack">
              <span>
                Grace Hopper
              </span>
              <span class="sk-table-cell-muted">
                grace@example.com
              </span>
            </span>
          </td>
          <td>
            <span class="sk-badge" data-status="success">
              Active
            </span>
          </td>
          <td data-numeric="true">
            980.50
          </td>
        </tr>
        <tr>
          <td>
            <span class="sk-table-cell-stack">
              <span>
                Alan Turing
              </span>
              <span class="sk-table-cell-muted">
                alan@example.com
              </span>
            </span>
          </td>
          <td>
            <span class="sk-badge" data-status="warning">
              Pending
            </span>
          </td>
          <td data-numeric="true">
            111.11
          </td>
        </tr>
        <tr>
          <td>
            <span class="sk-table-cell-stack">
              <span>
                Katherine Johnson
              </span>
              <span class="sk-table-cell-muted">
                katherine@example.com
              </span>
            </span>
          </td>
          <td>
            <span class="sk-badge" data-status="danger">
              Failed
            </span>
          </td>
          <td data-numeric="true">
            17.00
          </td>
        </tr>
        <tr>
          <td>
            <span class="sk-table-cell-stack">
              <span>
                Edsger Dijkstra
              </span>
              <span class="sk-table-cell-muted">
                edsger@example.com
              </span>
            </span>
          </td>
          <td>
            <span class="sk-badge" data-status="neutral">
              Archived
            </span>
          </td>
          <td data-numeric="true">
            2,006.75
          </td>
        </tr>
      </tbody>
    </table>
  </div>
  <nav class="sk-pagination" aria-label="Pagination">
    <p class="sk-pagination-info">
      11-15 of 240
    </p>
    <ul class="sk-pagination-list">
      <li>
        <a class="sk-page sk-page-step" href="?page=2" rel="prev">
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m15 18-6-6 6-6">
            </path>
          </svg>
          Previous
        </a>
      </li>
      <li>
        <a class="sk-page" href="?page=1" aria-label="Page 1">
          1
        </a>
      </li>
      <li>
        <a class="sk-page" href="?page=2" aria-label="Page 2">
          2
        </a>
      </li>
      <li>
        <span class="sk-page" aria-current="page">
          3
        </span>
      </li>
      <li>
        <a class="sk-page" href="?page=4" aria-label="Page 4">
          4
        </a>
      </li>
      <li>
        <span class="sk-page-gap" aria-hidden="true">
          &hellip;
        </span>
      </li>
      <li>
        <a class="sk-page" href="?page=48" aria-label="Page 48">
          48
        </a>
      </li>
      <li>
        <a class="sk-page sk-page-step" href="?page=4" rel="next">
          Next
          <svg class="sk-icon" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
            <path d="m9 18 6-6-6-6">
            </path>
          </svg>
        </a>
      </li>
    </ul>
  </nav>
</div>