Pagination

ui-pagination renders a <nav> with Previous, Next and numbered page controls from two numbers: the current page and the total number of pages. It always shows the first and last page, the pages within siblings of the current one, and an ellipsis for each gap. It works in two modes:

Previewindex.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Pagination demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/pagination.html"></import-element>

  <ui-pagination page="5" total="10"></ui-pagination>
</body>
</html>

Examples

Siblings

siblings sets how many pages are shown on each side of the current page. The default is 1.

Previewindex.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Pagination demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
  <style>
    .demo-stack {
      display: grid;
      gap: calc(var(--spacing) * 4);
    }
  </style>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/pagination.html"></import-element>

  <div class="demo-stack">
    <ui-pagination page="10" total="20" siblings="0"></ui-pagination>
    <ui-pagination page="10" total="20"></ui-pagination>
    <ui-pagination page="10" total="20" siblings="2"></ui-pagination>
  </div>
</body>
</html>

Few pages

When every page fits, no ellipsis is shown. Previous is disabled on the first page and Next on the last.

Previewindex.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Pagination demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/pagination.html"></import-element>

  <ui-pagination page="1" total="3"></ui-pagination>
</body>
</html>

With href, {page} in the pattern is replaced by each page number, so the numbers are crawlable links and work without script. The component does not change page itself in this mode. The next page load sets it.

<ui-pagination page="2" total="5" href="/invoices?page={page}"></ui-pagination>

Controlled from state

Bind page and total from state and read the new page from event.detail.page. Call event.preventDefault() on change to cancel the move, for example while data is still loading.

Previewindex.htmlpagination-state-demo.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Pagination demo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
  <script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
  <import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/pagination.html"></import-element>

  <import-element from="./pagination-state-demo.html"></import-element>
  <pagination-state-demo></pagination-state-demo>
</body>
</html>
<custom-element name="pagination-state-demo">
  <script>
    const list = useState({
      page: 1,
      total: 12,
      get range() {
        const start = (this.page - 1) * 10 + 1;
        return `Showing ${start} to ${start + 9} of 120 invoices`;
      },
    });

    function paged(event) {
      list.page = event.detail.page;
    }
  </script>
  <style>
    :host {
      display: grid;
      gap: calc(var(--spacing) * 3);
      justify-items: center;
    }
    p {
      margin: 0;
      font-size: var(--text-sm);
      color: var(--muted-foreground);
    }
  </style>
  <p><slot name="#list.range"></slot></p>
  <ui-pagination _page="#list.page" _total="#list.total" onchange="paged(event)"></ui-pagination>
</custom-element>

API

Attributes

Attribute Type Default Description
page number 1 The current page. Integer, at least 1. Updated by the component when href is not set.
total number 1 Number of pages. Integer, at least 1.
siblings number 1 Pages shown on each side of the current page. Integer, at least 0.
href string URL pattern for page links. {page} is replaced by the page number. When not set, the controls are buttons that update page.
label string "Pagination" Accessible name of the <nav> landmark.

Events

Event Detail Description
change { page: number } Fires before the page changes, from Previous, Next or a page number. Bubbles and is cancelable. preventDefault() keeps the current page and, in href mode, stops the link from navigating. Not fired for the current page or a page out of range.

CSS parts

Part Description
list The <ul> that lays out the controls.
previous The Previous control: a <button>, or an <a> in href mode.
next The Next control: a <button>, or an <a> in href mode.
page Each page number: a <button>, or an <a> in href mode. The current one has aria-current="page".

Accessibility

Edit this page on GitHub · View as Markdown