v1.0.0

<bmx-pagination>

Which page of a long list you are looking at, and how to get to another one.

17 properties · 1 events · 3 methods · 11 parts

Example

Page through 813 records. Watch the width of the control as you go: it does not change, so the button under your pointer stays where it was.

Showing rows 1–20 of 813.

The same control on a narrow screen, where a row of numbers has nowhere to go:

Show markup
<div class="row">
  <p style="margin: 0">
    Page through 813 records. Watch the width of the control as you go: it does not change, so the button under your
    pointer stays where it was.
  </p>
</div>

<div class="row">
  <bmx-pagination
    id="ex-pagination"
    total-items="813"
    page-size="20"
    page="1"
    show-edges
    show-summary
    page-sizes="10,20,50,100"
  ></bmx-pagination>
</div>

<div class="row">
  <span class="note" id="ex-pagination-out">Showing rows 1–20 of 813.</span>
</div>

<div class="row" style="margin-block-start: 1rem">
  <p style="margin: 0">The same control on a narrow screen, where a row of numbers has nowhere to go:</p>
</div>

<div class="row">
  <bmx-pagination total-items="813" page-size="20" page="7" compact show-edges></bmx-pagination>
</div>

<script type="module">
  await customElements.whenDefined('bmx-pagination');

  const out = document.getElementById('ex-pagination-out');

  /*
   * The event carries the row numbers as well as the page, because that is what
   * a query needs - `OFFSET 40 LIMIT 20` rather than "page 3". The component
   * fetches nothing itself: what a page *is* belongs to the data layer, which
   * knows about the API and the cache and this component never will.
   */
  document.getElementById('ex-pagination').addEventListener('bmxChange', event => {
    const { page, firstItem, lastItem, pageSize, reason } = event.detail;

    out.textContent =
      reason === 'size'
        ? `Now ${pageSize} per page — rows ${firstItem}–${lastItem}, on page ${page}.`
        : `Showing rows ${firstItem}–${lastItem} of 813.`;
  });
</script>
<bmx-pagination total-items="813" page-size="20" page="1"></bmx-pagination>

THE ONE COMPONENT HERE THAT IS GIVEN A NUMBER RATHER THAN A LIST

Everything else in this library is handed the things it draws. This one is handed a count, works out the rest, and its whole behaviour is therefore arithmetic: which page numbers to show, where the ellipses go, what a key press does, which page you land on when the page size changes. All of it is src/core/pagination.ts, tested without a browser, and the two rules worth knowing are there:

  • The control never changes width as you page through it. The naive window - the current page, some siblings, an ellipsis at each jump - is four items on page 1 and seven in the middle, so every button moves under the pointer as you use it. Here the width is fixed and the window slides.
  • An ellipsis never stands for a single page. 1 … 3 4 5 replaces "2" with a wider symbol offering a jump nobody can take, so the page is drawn instead. It is free: the slot was reserved either way.

WHAT IT DOES NOT DO

It does not fetch anything and it does not slice anything. It tells you which page was asked for; what a page is belongs to your data layer, which knows about your API and your cache and this component never will. Give it page back and it will draw what you decided.

Properties

PropertyAttributeTypeDefaultDescription
boundaries boundaries number 1 How many pages to pin at each end.
compact compact boolean false Draw only the previous and next buttons, with the page as text between. What a narrow screen wants. It is a property rather than a media query because the component cannot know how much room the page has given it - a container query in the consumer's stylesheet can set it, and often should.
disabled disabled boolean false Nothing can be pressed. The current page is still readable.
firstLabel first-label string 'First page' The labels on the four movement buttons, and on the size control.
label label string 'Pagination' The navigation landmark's accessible name.
lastLabel last-label string 'Last page'
nextLabel next-label string 'Next page'
page page number 1 The page being looked at, counting from 1.
pageSize page-size number 20 How many rows a page holds.
pageSizes page-sizes number[] | string [] The page sizes a reader may choose between. An empty list - the default - draws no size control at all. Given some, the control appears, and changing it keeps the row you are looking at on screen rather than the page number: at twenty per page, page 4 is rows 61 to 80, and at fifty per page those rows are on page 2. Landing on page 4 of the new pagination would show rows 151 to 200, which you have never seen. Accepts a comma-separated or JSON string as well, because an attribute is the only channel some templates have. See src/core/markup.ts.
pages pages number How many pages there are. Set this when your API tells you a page count and nothing else. When totalItems is given, that wins - it is the more precise fact, and it is what the summary and the page-size control need.
previousLabel previous-label string 'Previous page'
showEdges show-edges boolean false Whether to draw the jump-to-first and jump-to-last buttons.
showSummary show-summary boolean false Whether to draw the "21-40 of 813" summary. Needs totalItems.
siblings siblings number 1 How many pages to show either side of the current one.
sizeLabel size-label string 'Rows per page'
totalItems total-items number How many rows there are altogether.

Events

EventDetailDescription
bmxChange BmxPaginationChangeDetail Fired when the reader asks for a different page, or a different page size.

Methods

MethodSignatureDescription
goTo goTo(page: number) => Promise<void> Go to a page. Clamped, and silent if it is the page already showing.
next next() => Promise<void> Go forward one page, if there is one.
previous previous() => Promise<void> Go back one page, if there is one.

CSS shadow parts

PartDescription
base The <nav>.
current The page button for the page you are on. Carries part="page" as well.
first The button that jumps to page one.
gap An ellipsis.
last The button that jumps to the final page.
list The row of controls.
next The button that goes forward one page.
page One page button.
previous The button that goes back one page.
size The rows-per-page control.
summary The "21-40 of 813" text.

CSS custom properties

PropertyDescription
--bmx-pagination-background-hover A button's background under the pointer.
--bmx-pagination-border-color The border on a page button.
--bmx-pagination-color A page number's colour.
--bmx-pagination-current-background The background behind it.
--bmx-pagination-current-color The colour of the page you are on.
--bmx-pagination-gap Space between one control and the next.
--bmx-pagination-radius A button's corner radius.
--bmx-pagination-size The height and minimum width of a page button.
--bmx-pagination-summary-color The "21-40 of 813" text.