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

Pagination

OverviewStyleGuidelinesCodeAccessibilityDemos
PaginationAria CurrentColor ContextCompactMany PagesNo Numeric ControlOpen Compact SizeOpen CompactOpenOverflowRight To LeftSize CompactSizeVuePaginationAria CurrentColor ContextCompactMany PagesNo Numeric ControlOpen Compact SizeOpen CompactOpenOverflowRight To LeftSize CompactSizeVue

Pagination

import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination>
  <ol>
    <li><a href="?page=1">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">

Aria Current

Note

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. In real applications, this is handled during render or app logic.

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">

Color Context

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="open">
    <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">

Compact

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">

Many Pages

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">

No Numeric Control

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">

Open Compact Size

#constrain {
  max-width: var(--rh-breakpoint-xs-max, 767px);
}
import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination id="constrain" variant="open" 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">

Open Compact

#constrain {
  max-width: var(--rh-breakpoint-xs-max, 767px);
}
import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination id="constrain" variant="open">
  <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">

Open

import '@rhds/elements/rh-pagination/rh-pagination.js';
<rh-pagination variant="open">
  <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">

Overflow

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">

Right To Left

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">

Size Compact

#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">

Size

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">

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">
© 2025 Red Hat Deploys by Netlify