Open demo

CSS code

HTML
<div><span class="lbl">Numbered pages</span>
<div class="tcard">
  <table class="tbl mini"><caption class="sr-only">Invoices, rows 41 to 60 of 248</caption><tbody>
    <tr><th scope="row">Meridian Ltd</th><td class="num">$584.40</td></tr>
    <tr><th scope="row">Halcyon Studio</th><td class="num">$1,220.00</td></tr>
  </tbody></table>
  <nav class="pg" aria-label="Numbered pagination">
    <span class="rng">41–60 of 248</span>
    <span class="sp">
      <button type="button" aria-label="Previous page">‹</button>
      <a href="#" aria-label="Page 1">1</a><span class="gap">…</span><a href="#" aria-label="Page 2">2</a>
      <a href="#" aria-label="Page 3" aria-current="page">3</a><a href="#" aria-label="Page 4">4</a><span class="gap">…</span><a href="#" aria-label="Page 13">13</a>
      <button type="button" aria-label="Next page">›</button>
    </span>
  </nav>
</div></div>

<div><span class="lbl">Rows per page</span>
<div class="tcard">
  <table class="tbl mini"><caption class="sr-only">Invoices, rows 41 to 60 of 248</caption><tbody>
    <tr><th scope="row">Northwind Co</th><td class="num">$318.75</td></tr>
    <tr><th scope="row">Fieldnote</th><td class="num">$2,940.00</td></tr>
  </tbody></table>
  <nav class="pg" aria-label="Pagination with rows per page">
    <label class="rpp">Rows per page <select><option>20</option><option>50</option><option>100</option></select></label>
    <span class="sp">
      <span class="rng">41–60 of 248</span>
      <button type="button" aria-label="Previous page">‹</button>
      <button type="button" aria-label="Next page">›</button>
    </span>
  </nav>
</div></div>

<div><span class="lbl">Cursor (previous / next only)</span>
<div class="tcard">
  <table class="tbl mini"><caption class="sr-only">Invoices, first 20 results</caption><tbody>
    <tr><th scope="row">Copperleaf</th><td class="num">$470.00</td></tr>
    <tr><th scope="row">Ridgeway</th><td class="num">$1,905.20</td></tr>
  </tbody></table>
  <nav class="pg" aria-label="Cursor pagination">
    <span class="rng">Showing 20 results</span>
    <span class="sp">
      <button type="button" disabled>‹ Previous</button>
      <button type="button">Next ›</button>
    </span>
  </nav>
</div></div>

<div><span class="lbl">Load more</span>
<div class="tcard">
  <table class="tbl mini"><caption class="sr-only">Invoices, first 40 of 248</caption><tbody>
    <tr><th scope="row">Ashgrove</th><td class="num">$88.00</td></tr>
    <tr><th scope="row">Bellweather</th><td class="num">$3,410.00</td></tr>
  </tbody></table>
  <button class="more" type="button">Load 20 more (208 remaining)</button>
</div></div>
CSS
/* Four table footers: numbered pages, rows per page, cursor (previous and next only) and load more.
   The footer is a <nav> with its own label; the current page link carries aria-current="page". */
.tcard{background:#fff;border:1px solid #e7e9f0;border-radius:14px;overflow:hidden;margin-bottom:14px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
.tbl{width:100%;border-collapse:collapse;font-size:.89rem}
.tbl td,.tbl th{padding:9px 16px;border-bottom:1px solid #f2f4f7;color:#3c4048;text-align:left;font-weight:400}
.tbl .num{font-variant-numeric:tabular-nums;text-align:right}
.pg{display:flex;align-items:center;gap:12px;padding:12px 16px;flex-wrap:wrap}
.pg .rng{font-size:.84rem;color:#667085}
.pg .sp{margin-left:auto;display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pg button,.pg a{border:1px solid #e4e7ec;background:#fff;border-radius:8px;min-width:34px;height:34px;
  display:grid;place-items:center;font:inherit;font-size:.85rem;font-weight:600;color:#475467;
  cursor:pointer;padding:0 10px;text-decoration:none}
.pg button:hover,.pg a:hover{background:#f7f8fa;color:#101828}
.pg button:focus-visible,.pg a:focus-visible,.pg select:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.pg a[aria-current]{background:#101828;border-color:#101828;color:#fff}
.pg button:disabled{color:#c3c9d5;cursor:not-allowed;background:#fafbfc}
.pg .gap{min-width:20px;height:34px;display:grid;place-items:center;font-size:.85rem;font-weight:600;color:#667085}
.pg .rpp{font-size:.84rem;color:#667085;display:flex;align-items:center;gap:8px}
.pg select{border:1px solid #8b93a3;border-radius:8px;padding:7px 9px;font:inherit;font-size:.85rem;
  color:#475467;background:#fff;cursor:pointer}
.more{display:block;width:100%;padding:13px;border:0;border-top:1px solid #eceef3;background:#fafbfc;
  font:inherit;font-size:.87rem;font-weight:700;color:#4f46e5;cursor:pointer}
.more:hover{background:#f2f4f8}
.more:focus-visible{outline:2px solid #4f46e5;outline-offset:-2px}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div><span class="lbl">Numbered pages</span>
<div class="card tcard overflow-hidden">
  <table class="table align-middle mb-0 tbl mini"><caption class="visually-hidden">Invoices, rows 41 to 60 of 248</caption><tbody>
    <tr><th scope="row">Meridian Ltd</th><td class="text-end num">$584.40</td></tr>
    <tr><th scope="row">Halcyon Studio</th><td class="text-end num">$1,220.00</td></tr>
  </tbody></table>
  <nav class="pg d-flex flex-wrap align-items-center" aria-label="Numbered pagination">
    <span class="rng">41–60 of 248</span>
    <ul class="pagination flex-wrap mb-0 ms-auto">
      <li class="page-item"><button class="page-link" type="button" aria-label="Previous page">‹</button></li>
      <li class="page-item"><a class="page-link" href="#" aria-label="Page 1">1</a></li><li class="page-item gap"><span class="page-link">…</span></li><li class="page-item"><a class="page-link" href="#" aria-label="Page 2">2</a></li>
      <li class="page-item active"><a class="page-link" href="#" aria-label="Page 3" aria-current="page">3</a></li><li class="page-item"><a class="page-link" href="#" aria-label="Page 4">4</a></li><li class="page-item gap"><span class="page-link">…</span></li><li class="page-item"><a class="page-link" href="#" aria-label="Page 13">13</a></li>
      <li class="page-item"><button class="page-link" type="button" aria-label="Next page">›</button></li>
    </ul>
  </nav>
</div></div>

<div><span class="lbl">Rows per page</span>
<div class="card tcard overflow-hidden">
  <table class="table align-middle mb-0 tbl mini"><caption class="visually-hidden">Invoices, rows 41 to 60 of 248</caption><tbody>
    <tr><th scope="row">Northwind Co</th><td class="text-end num">$318.75</td></tr>
    <tr><th scope="row">Fieldnote</th><td class="text-end num">$2,940.00</td></tr>
  </tbody></table>
  <nav class="pg d-flex flex-wrap align-items-center" aria-label="Pagination with rows per page">
    <label class="rpp d-flex align-items-center">Rows per page <select class="form-select form-select-sm"><option>20</option><option>50</option><option>100</option></select></label>
    <span class="ms-auto d-flex flex-wrap align-items-center gap-2 sp">
      <span class="rng">41–60 of 248</span>
      <ul class="pagination mb-0">
        <li class="page-item"><button class="page-link" type="button" aria-label="Previous page">‹</button></li>
        <li class="page-item"><button class="page-link" type="button" aria-label="Next page">›</button></li>
      </ul>
    </span>
  </nav>
</div></div>

<div><span class="lbl">Cursor (previous / next only)</span>
<div class="card tcard overflow-hidden">
  <table class="table align-middle mb-0 tbl mini"><caption class="visually-hidden">Invoices, first 20 results</caption><tbody>
    <tr><th scope="row">Copperleaf</th><td class="text-end num">$470.00</td></tr>
    <tr><th scope="row">Ridgeway</th><td class="text-end num">$1,905.20</td></tr>
  </tbody></table>
  <nav class="pg d-flex flex-wrap align-items-center" aria-label="Cursor pagination">
    <span class="rng">Showing 20 results</span>
    <ul class="pagination flex-wrap mb-0 ms-auto">
      <li class="page-item disabled"><button class="page-link" type="button" disabled>‹ Previous</button></li>
      <li class="page-item"><button class="page-link" type="button">Next ›</button></li>
    </ul>
  </nav>
</div></div>

<div><span class="lbl">Load more</span>
<div class="card tcard overflow-hidden">
  <table class="table align-middle mb-0 tbl mini"><caption class="visually-hidden">Invoices, first 40 of 248</caption><tbody>
    <tr><th scope="row">Ashgrove</th><td class="text-end num">$88.00</td></tr>
    <tr><th scope="row">Bellweather</th><td class="text-end num">$3,410.00</td></tr>
  </tbody></table>
  <button class="btn more w-100" type="button">Load 20 more (208 remaining)</button>
</div></div>
CSS
/* Bootstrap .card + .table with .pagination footers. The joined Bootstrap pagination is split into
   separate rounded buttons, and colours come in through the --bs-pagination-* variables. */
.tcard{--bs-card-border-color:#e7e9f0;--bs-card-border-radius:14px;--bs-card-bg:#fff;margin-bottom:14px}
.tbl{--bs-table-color:#3c4048;--bs-table-bg:#fff;--bs-table-border-color:#f2f4f7;font-size:.89rem}
.tbl > :not(caption) > * > *{padding:9px 16px;font-weight:400}
.tbl .num{font-variant-numeric:tabular-nums}
.pg{gap:12px;padding:12px 16px}
.pg .rng{font-size:.84rem;color:#667085}
.pg .pagination{--bs-pagination-padding-x:10px;--bs-pagination-padding-y:0;--bs-pagination-font-size:.85rem;
  --bs-pagination-color:#475467;--bs-pagination-bg:#fff;--bs-pagination-border-color:#e4e7ec;
  --bs-pagination-border-radius:8px;--bs-pagination-hover-color:#101828;--bs-pagination-hover-bg:#f7f8fa;
  --bs-pagination-hover-border-color:#e4e7ec;--bs-pagination-focus-color:#101828;--bs-pagination-focus-bg:#fff;
  --bs-pagination-focus-box-shadow:0 0 0 2px #fff,0 0 0 4px #4f46e5;--bs-pagination-active-color:#fff;
  --bs-pagination-active-bg:#101828;--bs-pagination-active-border-color:#101828;
  --bs-pagination-disabled-color:#c3c9d5;--bs-pagination-disabled-bg:#fafbfc;--bs-pagination-disabled-border-color:#e4e7ec;
  gap:6px}
.pg .page-item .page-link{min-width:34px;height:34px;display:grid;place-items:center;font-weight:600;
  line-height:normal;margin-left:0;border-radius:8px}
.pg .page-item.disabled .page-link{cursor:not-allowed}
.pg .page-item.gap .page-link{min-width:20px;padding:0;border-color:transparent;background:none;color:#667085}
.pg .rpp{font-size:.84rem;color:#667085;gap:8px}
.pg .form-select{width:auto;font-size:.85rem;color:#475467;border-color:#8b93a3;border-radius:8px;
  padding-top:7px;padding-bottom:7px;padding-left:9px}
.pg .form-select:focus{box-shadow:none;border-color:#8b93a3}
.pg .form-select:focus-visible{outline:2px solid #4f46e5;outline-offset:2px}
.tcard .more{--bs-btn-padding-y:13px;--bs-btn-font-size:.87rem;--bs-btn-font-weight:700;--bs-btn-line-height:normal;
  --bs-btn-color:#4f46e5;--bs-btn-bg:#fafbfc;--bs-btn-hover-color:#4f46e5;--bs-btn-hover-bg:#f2f4f8;
  --bs-btn-active-color:#4f46e5;--bs-btn-active-bg:#eef0f4;--bs-btn-border-radius:0;--bs-btn-border-width:0;
  --bs-btn-focus-box-shadow:inset 0 0 0 2px #4f46e5;border-top:1px solid #eceef3}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<div><span class="mb-[9px] block text-[.72rem] font-bold tracking-[.08em] text-[#667085] uppercase">Numbered pages</span>
<div class="mb-3.5 overflow-hidden rounded-[14px] border border-[#e7e9f0] bg-white">
  <table class="w-full border-collapse text-[.89rem] text-[#3c4048] [&_tr]:border-b [&_tr]:border-[#f2f4f7]"><caption class="sr-only">Invoices, rows 41 to 60 of 248</caption><tbody>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Meridian Ltd</th><td class="px-4 py-[9px] text-right tabular-nums">$584.40</td></tr>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Halcyon Studio</th><td class="px-4 py-[9px] text-right tabular-nums">$1,220.00</td></tr>
  </tbody></table>
  <nav class="flex flex-wrap items-center gap-3 px-4 py-3" aria-label="Numbered pagination">
    <span class="text-[.84rem] text-[#667085]">41–60 of 248</span>
    <span class="ml-auto flex flex-wrap items-center gap-1.5">
      <button type="button" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] disabled:cursor-not-allowed disabled:bg-[#fafbfc] disabled:text-[#c3c9d5]" aria-label="Previous page">‹</button>
      <a href="#" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] no-underline" aria-label="Page 1">1</a><span class="grid h-[34px] min-w-5 place-items-center text-[.85rem] font-semibold text-[#667085]">…</span><a href="#" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] no-underline" aria-label="Page 2">2</a>
      <a href="#" class="grid h-[34px] min-w-[34px] place-items-center rounded-lg border border-[#101828] bg-[#101828] px-2.5 text-[.85rem] font-semibold text-white no-underline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5]" aria-label="Page 3" aria-current="page">3</a><a href="#" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] no-underline" aria-label="Page 4">4</a><span class="grid h-[34px] min-w-5 place-items-center text-[.85rem] font-semibold text-[#667085]">…</span><a href="#" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] no-underline" aria-label="Page 13">13</a>
      <button type="button" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] disabled:cursor-not-allowed disabled:bg-[#fafbfc] disabled:text-[#c3c9d5]" aria-label="Next page">›</button>
    </span>
  </nav>
</div></div>

<div><span class="mb-[9px] block text-[.72rem] font-bold tracking-[.08em] text-[#667085] uppercase">Rows per page</span>
<div class="mb-3.5 overflow-hidden rounded-[14px] border border-[#e7e9f0] bg-white">
  <table class="w-full border-collapse text-[.89rem] text-[#3c4048] [&_tr]:border-b [&_tr]:border-[#f2f4f7]"><caption class="sr-only">Invoices, rows 41 to 60 of 248</caption><tbody>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Northwind Co</th><td class="px-4 py-[9px] text-right tabular-nums">$318.75</td></tr>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Fieldnote</th><td class="px-4 py-[9px] text-right tabular-nums">$2,940.00</td></tr>
  </tbody></table>
  <nav class="flex flex-wrap items-center gap-3 px-4 py-3" aria-label="Pagination with rows per page">
    <label class="flex items-center gap-2 text-[.84rem] text-[#667085]">Rows per page <select class="cursor-pointer rounded-lg border border-[#8b93a3] px-[9px] py-[7px] text-[.85rem] text-[#475467] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5]"><option>20</option><option>50</option><option>100</option></select></label>
    <span class="ml-auto flex flex-wrap items-center gap-1.5">
      <span class="text-[.84rem] text-[#667085]">41–60 of 248</span>
      <button type="button" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] disabled:cursor-not-allowed disabled:bg-[#fafbfc] disabled:text-[#c3c9d5]" aria-label="Previous page">‹</button>
      <button type="button" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] disabled:cursor-not-allowed disabled:bg-[#fafbfc] disabled:text-[#c3c9d5]" aria-label="Next page">›</button>
    </span>
  </nav>
</div></div>

<div><span class="mb-[9px] block text-[.72rem] font-bold tracking-[.08em] text-[#667085] uppercase">Cursor (previous / next only)</span>
<div class="mb-3.5 overflow-hidden rounded-[14px] border border-[#e7e9f0] bg-white">
  <table class="w-full border-collapse text-[.89rem] text-[#3c4048] [&_tr]:border-b [&_tr]:border-[#f2f4f7]"><caption class="sr-only">Invoices, first 20 results</caption><tbody>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Copperleaf</th><td class="px-4 py-[9px] text-right tabular-nums">$470.00</td></tr>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Ridgeway</th><td class="px-4 py-[9px] text-right tabular-nums">$1,905.20</td></tr>
  </tbody></table>
  <nav class="flex flex-wrap items-center gap-3 px-4 py-3" aria-label="Cursor pagination">
    <span class="text-[.84rem] text-[#667085]">Showing 20 results</span>
    <span class="ml-auto flex flex-wrap items-center gap-1.5">
      <button type="button" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] disabled:cursor-not-allowed disabled:bg-[#fafbfc] disabled:text-[#c3c9d5]" disabled>‹ Previous</button>
      <button type="button" class="grid h-[34px] min-w-[34px] cursor-pointer place-items-center rounded-lg border border-[#e4e7ec] bg-white px-2.5 text-[.85rem] font-semibold text-[#475467] hover:bg-[#f7f8fa] hover:text-[#101828] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[#4f46e5] disabled:cursor-not-allowed disabled:bg-[#fafbfc] disabled:text-[#c3c9d5]">Next ›</button>
    </span>
  </nav>
</div></div>

<div><span class="mb-[9px] block text-[.72rem] font-bold tracking-[.08em] text-[#667085] uppercase">Load more</span>
<div class="mb-3.5 overflow-hidden rounded-[14px] border border-[#e7e9f0] bg-white">
  <table class="w-full border-collapse text-[.89rem] text-[#3c4048] [&_tr]:border-b [&_tr]:border-[#f2f4f7]"><caption class="sr-only">Invoices, first 40 of 248</caption><tbody>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Ashgrove</th><td class="px-4 py-[9px] text-right tabular-nums">$88.00</td></tr>
    <tr><th scope="row" class="px-4 py-[9px] text-left font-normal">Bellweather</th><td class="px-4 py-[9px] text-right tabular-nums">$3,410.00</td></tr>
  </tbody></table>
  <button class="block w-full cursor-pointer border-t border-[#eceef3] bg-[#fafbfc] p-[13px] text-[.87rem] font-bold text-[#4f46e5] hover:bg-[#f2f4f8] focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-[#4f46e5]" type="button">Load 20 more (208 remaining)</button>
</div></div>

About this set

Four table footers, each suited to a different kind of data source, shown under the same two-row invoice table. Numbered pages shows the range, 41 to 60 of 248, then previous and next buttons around page links with the first and last page and gaps, and the current page filled in dark slate. Rows per page puts a page size select on the left and the range with previous and next on the right. Cursor pagination has only previous and next, with previous disabled on the first page, because a cursor-based API cannot jump to page 7 or report a total. Load more is a full-width button that says how many rows remain. Choose by what your API can do: an offset endpoint can number pages, a cursor endpoint cannot, and load more suits feeds that are read from the top. Each footer is a nav with its own label, page links carry labels such as Page 3, and the current one has aria-current=”page”. The Bootstrap version uses .pagination with the joined buttons split into separate rounded ones, and a .form-select for the page size.

What’s included

  • Numbered pages with gaps and a current page
  • Rows per page select with a range
  • Cursor pagination with previous and next only
  • Full-width load more button with a remaining count
  • Bootstrap version built on .pagination and .form-select

Accessibility

Each footer is a nav landmark with a unique aria-label, page links have aria-label values like Page 3 and the current page has aria-current="page". Arrow-only buttons are labelled Previous page and Next page, the select is labelled by its visible text and has a 3:1 border, and every control shows a 2px focus outline. Each mini table has a caption and row headers. Nothing animates.

Customise it

The current page colour is #101828 on a[aria-current] (plain CSS), --bs-pagination-active-bg (Bootstrap) or the classes on the current link (Tailwind). Button size is the 34px min-width and height, and the load more colour is #4f46e5.