Skip to main content Home About the Design SystemRoadmap OverviewDesignersDevelopers OverviewColorGridIconographyInteractionsSpacingTypography Overview Global colorBox shadowTypographyBorderOpacitySpaceLengthIconBreakpointsMedia queries All elements Accordion Alert Announcement Audio player Avatar Back to top Badge Blockquote Breadcrumb Button group Button Card Chip Code block Call to action Dialog Disclosure Footer Health index Icon Jump links Menu dropdown Navigation link Navigation (primary) Navigation (secondary) Navigation (vertical) Pagination PopoverPlanned Progress stepper Readtime Scheme toggle Select Site status Skeleton Skip link Spinner Statistic Subnavigation Surface Switch Table Tabs Tag Tile Timestamp Tooltip Video embed OverviewColor PalettesCustomizingDevelopers All PatternsAccordionAlertCall to ActionCardFilterFormLink with iconLogo wallSearch barSticky bannerSticky cardTabsTagTile All Personalization PatternsAnnouncement FundamentalsAccessibility toolsAssistive technologiesCI/CDContentContributorsDesignDevelopmentManual testingResourcesScreen readers Design/code status Release notes Get support

Pagination

OverviewStyleGuidelinesCodeAccessibilityDemos
PaginationAria CurrentBorderless Compact SizeBorderless CompactBorderlessColor ContextCompactMany PagesNo Numeric ControlOverflowRight To LeftSize CompactSizeVuePaginationAria CurrentBorderless Compact SizeBorderless CompactBorderlessColor ContextCompactMany PagesNo Numeric ControlOverflowRight To LeftSize CompactSizeVue

Pagination

Default pagination with page links and numeric input.

import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination>
  <ol>
    <li><a href="./">1</a></li>
    <li><a href="?page=2">2</a></li>
    <li><a href="?page=3">3</a></li>
    <li><a href="?page=4">4</a></li>
    <li><a href="?page=5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination>
    <ol>
      <li><a href="./">1</a></li>
      <li><a href="?page=2">2</a></li>
      <li><a href="?page=3">3</a></li>
      <li><a href="?page=4">4</a></li>
      <li><a href="?page=5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Aria Current

Page 3 is marked with aria-current="page" by default, regardless of the URL. This takes precedence over the URL hash. When the URL hash changes, aria-current="page" is set on the correct link.

import '@rhds/elements/rh-pagination/rh-pagination.js';
window.addEventListener('hashchange', () => {
  const hash = window.location.hash;
  const links = document.querySelectorAll('rh-pagination li a');
  const hashLink = document.querySelector(`rh-pagination li a[href="${hash}"]`);
  for (const link of links) {
    if (link === hashLink) {
      continue;
    }
    link.removeAttribute('aria-current');
  }
  hashLink.setAttribute('aria-current', 'page');
  // slotted content changed lets request an update
  const pagination = document.querySelector('rh-pagination');
  pagination.requestUpdate();
});
<rh-pagination>
  <ol>
    <li><a href="#1">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3" aria-current="page">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination>
    <ol>
      <li><a href="#1">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3" aria-current="page">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Borderless Compact Size

Compact pagination in the borderless variant with small size.

#constrain {
  max-width: var(--rh-breakpoint-xs-max, 767px);
}
import "@rhds/elements/rh-pagination/rh-pagination.js";
<rh-pagination id="constrain" variant="borderless" size="sm">
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination id="constrain" variant="borderless" size="sm">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Borderless Compact

Compact pagination in the borderless variant style.

#constrain {
  max-width: var(--rh-breakpoint-xs-max, 767px);
}
import "@rhds/elements/rh-pagination/rh-pagination.js";
<rh-pagination id="constrain" variant="borderless">
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination id="constrain" variant="borderless">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Borderless

Pagination in the borderless variant with transparent button backgrounds.

import "@rhds/elements/rh-pagination/rh-pagination.js";
<rh-pagination variant="borderless">
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination variant="borderless">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Color Context

Pagination rendered in light and dark color contexts.

import '@rhds/elements/lib/elements/rh-context-demo/rh-context-demo.js';
import '@rhds/elements/rh-pagination/rh-pagination.js';
rh-context-demo > * {
  margin-block-end: var(--rh-space-2xl, 32px);
}
<rh-context-demo>
  <rh-pagination>
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </rh-pagination>

  <rh-pagination variant="borderless">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </rh-pagination>

  <rh-pagination size="sm">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </rh-pagination>
</rh-context-demo>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { ContextDemo } from "@rhds/elements/react/rh-context-demo/rh-context-demo.js";
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <ContextDemo>
    <Pagination>
      <ol>
        <li><a href="#">1</a></li>
        <li><a href="#2">2</a></li>
        <li><a href="#3">3</a></li>
        <li><a href="#4">4</a></li>
        <li><a href="#5">5</a></li>
      </ol>
    </Pagination>
    <Pagination variant="borderless">
      <ol>
        <li><a href="#">1</a></li>
        <li><a href="#2">2</a></li>
        <li><a href="#3">3</a></li>
        <li><a href="#4">4</a></li>
        <li><a href="#5">5</a></li>
      </ol>
    </Pagination>
    <Pagination size="sm">
      <ol>
        <li><a href="#">1</a></li>
        <li><a href="#2">2</a></li>
        <li><a href="#3">3</a></li>
        <li><a href="#4">4</a></li>
        <li><a href="#5">5</a></li>
      </ol>
    </Pagination>
  </ContextDemo>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Compact

Compact pagination layout with numeric input between stepper buttons.

import '@rhds/elements/rh-pagination/rh-pagination.js';
#constrain {
  max-width: var(--rh-breakpoint-xs-max, 767px);
}
<rh-pagination id="constrain">
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination id="constrain">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Many Pages

Pagination with a large number of pages to test truncation behavior.

rh-pagination {
  margin-block-end: var(--rh-space-lg, 16px);
}
import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination>
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
    <li><a href="#6">6</a></li>
    <li><a href="#7">7</a></li>
    <li><a href="#8">8</a></li>
    <li><a href="#9">9</a></li>
    <li><a href="#10">10</a></li>
    <li><a href="#11">11</a></li>
    <li><a href="#12">12</a></li>
    <li><a href="#13">13</a></li>
    <li><a href="#14">14</a></li>
    <li><a href="#15">15</a></li>
    <li><a href="#16">16</a></li>
    <li><a href="#17">17</a></li>
    <li><a href="#18">18</a></li>
    <li><a href="#19">19</a></li>
    <li><a href="#20">20</a></li>
  </ol>
</rh-pagination>

<p>Paginators with many pages must overflow.</p>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination>
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
      <li><a href="#6">6</a></li>
      <li><a href="#7">7</a></li>
      <li><a href="#8">8</a></li>
      <li><a href="#9">9</a></li>
      <li><a href="#10">10</a></li>
      <li><a href="#11">11</a></li>
      <li><a href="#12">12</a></li>
      <li><a href="#13">13</a></li>
      <li><a href="#14">14</a></li>
      <li><a href="#15">15</a></li>
      <li><a href="#16">16</a></li>
      <li><a href="#17">17</a></li>
      <li><a href="#18">18</a></li>
      <li><a href="#19">19</a></li>
      <li><a href="#20">20</a></li>
    </ol>
  </Pagination>
  <p>Paginators with many pages must overflow.</p>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

No Numeric Control

Pagination without the numeric page input control visible.

rh-pagination::part(numeric) {
  display: none;
}
import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination>
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination>
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Overflow

Pagination demonstrating truncation overflow with many pages.

fieldset,
p,
dd {
  margin-block-end: var(--rh-space-lg, 16px)
}
import '@rhds/elements/rh-button/rh-button.js';
import '@rhds/elements/rh-pagination/rh-pagination.js';

const $ = s => document.querySelector(s);
const $$ = s => document.querySelectorAll(s);

for (const element of $$('rh-pagination')) {
  element.addEventListener('click', event => {
    const link = event.composedPath().find(x => x instanceof HTMLAnchorElement);
    if (link) {
      event.preventDefault();
      history.pushState(null, link.innerText, link.href);
      element.requestUpdate();
    }
  });
}

$('#add')?.addEventListener('click', function() {
  const link = document.createElement('a');
  const item = document.createElement('li');
  item.append(link);
  const i = $$('rh-pagination li').length + 1;
  link.href = `#${i}`;
  link.textContent = i;
  $('rh-pagination ol').append(item);
  $('rh-pagination').requestUpdate();
});

$('#remove')?.addEventListener('click', function() {
  $('rh-pagination li:last-child')?.remove?.();
});
<rh-pagination>
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<p>Paginators with 5 or fewer pages should not overflow, meaning all links should be visible.
  Once a paginator has more than 5 pages, then it must overflow, meaning some links will be hidden.
  Paginators with 9 or more pages will overflow on boths ends.</p>

<dl>
  <dt>With 5 or fewer pages</dt>
  <dd>No overflow</dd>
  <dt>With more than 5 but fewer than 9 pages</dt>
  <dd>Overflow on one side</dd>
  <dt>With more than 9 pages, active page is less than 6</dt>
  <dd>Overflow end</dd>
  <dt>With more than 9 pages, active page is greater than 6</dt>
  <dd>Overflow both</dd>
  <dt>With more than 9 pages, active page is greater than 5 less than the total (e.g. 16/20)</dt>
  <dd>Overflow start</dd>
</dl>

<fieldset>
  <legend>Adjust pages</legend>
  <rh-button id="add">Add Page</rh-button>
  <rh-button id="remove" danger="">Remove Page</rh-button>
</fieldset>



<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Button } from "@rhds/elements/react/rh-button/rh-button.js";
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination>
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <p>Paginators with 5 or fewer pages should not overflow, meaning all links should be visible.
    Once a paginator has more than 5 pages, then it must overflow, meaning some links will be hidden.
    Paginators with 9 or more pages will overflow on boths ends.</p>
  <dl>
    <dt>With 5 or fewer pages</dt>
    <dd>No overflow</dd>
    <dt>With more than 5 but fewer than 9 pages</dt>
    <dd>Overflow on one side</dd>
    <dt>With more than 9 pages, active page is less than 6</dt>
    <dd>Overflow end</dd>
    <dt>With more than 9 pages, active page is greater than 6</dt>
    <dd>Overflow both</dd>
    <dt>With more than 9 pages, active page is greater than 5 less than the total (e.g. 16/20)</dt>
    <dd>Overflow start</dd>
  </dl>
  <fieldset>
    <legend>Adjust pages</legend>
    <Button id="add">Add Page</Button>
    <Button id="remove" danger>Remove Page</Button>
  </fieldset>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Right To Left

Pagination in right-to-left (RTL) direction layout.

import '@rhds/elements/rh-pagination/rh-pagination.js';
<p>צריך להיראות יותר טוב</p>
<rh-pagination id="rtl-pagination" dir="rtl">
  <span slot="go-to-page">עבור לדף</span>
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <p>צריך להיראות יותר טוב</p>
  <Pagination id="rtl-pagination" dir="rtl">
    <span slot="go-to-page">עבור לדף</span>
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Size Compact

Compact pagination in small size with inline numeric input.

#constrain {
  max-width: var(--rh-breakpoint-xs-max, 767px);
}
import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination id="constrain" size="sm">
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination id="constrain" size="sm">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Size

Pagination in small size variant with reduced button dimensions.

import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination size="sm">
  <ol>
    <li><a href="#">1</a></li>
    <li><a href="#2">2</a></li>
    <li><a href="#3">3</a></li>
    <li><a href="#4">4</a></li>
    <li><a href="#5">5</a></li>
  </ol>
</rh-pagination>

<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <Pagination size="sm">
    <ol>
      <li><a href="#">1</a></li>
      <li><a href="#2">2</a></li>
      <li><a href="#3">3</a></li>
      <li><a href="#4">4</a></li>
      <li><a href="#5">5</a></li>
    </ol>
  </Pagination>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);

Vue

Demonstration of the pagination element in a simple Vue 3 application.

import '@rhds/elements/rh-pagination/rh-pagination.js';
import { createApp } from 'vue/dist/vue.esm-browser.js';

const app = createApp({
  data() {
    return {
      message: 'You are currently on page',
      pages: [1, 2, 3, 4, 5],
      currentPage: 3
    }
  },
  mounted() {
    const pagination = document.querySelector('rh-pagination');

    // get current Page by using the aria-current attribute
    const currentPage = pagination.querySelector('li a[aria-current="page"]');
    if (currentPage) {
      this.currentPage = new URL(currentPage.href).hash.slice(1);
    }

    // Add hash change listener
    window.addEventListener('hashchange', () => {
      const hash = window.location.hash;
      this.currentPage = hash.slice(1);
      const links = pagination.querySelectorAll('li a');
      const hashLink = pagination.querySelector(`li a[href="${hash}"]`);
      for (const link of links) {
        if (link === hashLink) {
continue;
        }
        link.removeAttribute('aria-current');
      }
      hashLink.setAttribute('aria-current', 'page');
      pagination.requestUpdate();
    });
  },
});
app.mount('#app');
<div id="app">
  <rh-pagination>
    <ol>
      <li v-for="pageNum in pages" :key="pageNum">
        <a :href="`#${pageNum}`" :aria-current="pageNum == currentPage ? 'page' : null" v-text="pageNum"></a>
      </li>
    </ol>
  </rh-pagination>

  <span v-text="message"></span> <span v-text="currentPage"></span>
</div>



<link rel="stylesheet" href="../rh-pagination-lightdom.css">
import { Pagination } from "@rhds/elements/react/rh-pagination/rh-pagination.js";

// NOTE: React 19+ does not require these wrapper imports.
// You can use the custom elements directly as-is.

export const Demo = () => (
  <div id="app">
    <Pagination>
      <ol>
        <li v-for="pageNum in pages" :key="pageNum">
<a :href="`#${pageNum}`" :aria-current="pageNum == currentPage ? 'page' : null" v-text="pageNum" />
        </li>
      </ol>
    </Pagination>
    <span v-text="message" />
    <span v-text="currentPage" />
  </div>
  <link rel="stylesheet" href="../rh-pagination-lightdom.css" />
);
© 2026 Red Hat Deploys by Netlify