Skip to main content

Pagination

Pagination is used to navigate a series of pages in a linear or semi-linear manner, allowing you to display a portion of information and avoid overwhelming the user with too much information.

Variants

Long pagination

<nav class="ons-pagination " arial-label="Pagination (Page 5 of 35)">
  <div class="ons-pagination__position">Page 5 of 35</div>
  <ul class="ons-pagination__items">
    <li class="ons-pagination__item ons-pagination__item--previous">
      <a href="#0" class="ons-pagination__link" rel="prev" aria-label="Go to the previous page (Page 4)">Previous</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#0" class="ons-pagination__link" aria-label="Go to the first page (Page 1)">1</a>
    </li>
    <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
    <li class="ons-pagination__item">
      <a href="#0" class="ons-pagination__link" aria-label="Go to page 3">3</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#0" class="ons-pagination__link" aria-label="Go to page 4" rel="prev">4</a>
    </li>
    <li class="ons-pagination__item ons-pagination__item--current">
      <a href="#0" class="ons-pagination__link" aria-current="true" aria-label="Current page (Page 5 of 35)">5</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#0" class="ons-pagination__link" aria-label="Go to page 6" rel="next">6</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#0" class="ons-pagination__link" aria-label="Go to page 7">7</a>
    </li>
    <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
    <li class="ons-pagination__item">
      <a href="#0" class="ons-pagination__link" aria-label="Go to the last page (Page 35)">35</a>
    </li>
    <li class="ons-pagination__item ons-pagination__item--next">
      <a href="#0" class="ons-pagination__link" rel="next" aria-label="Go to the next page (Page 6)">Next</a>
    </li>
  </ul>
</nav>
{% from "components/pagination/_macro.njk" import onsPagination %}

{{
    onsPagination({
        "previous": "Previous",
        "next": "Next",
        "pages": [
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0",
                "current": true
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            },
            {
                "url": "#0"
            }
        ]
    })
}}
Name Type Required Description
pages Array true An array of all pages
previous string true Text for the previous button
next string true Text for the next button
classes string false Classes to add to the pagination
hideRangeIndicator boolean false When set to true will hide the range indicator on desktop

Page

Name Type Required Description
url string true URL for the page
current boolean false If this is the current page set to true
{% macro onsPagination(params) %}
  {% set currentPageIndex = "" %}
  {% for page in params.pages %}
      {% if page.current is defined and page.current %}
          {% set currentPageIndex = loop.index %}
      {% endif %}
  {% endfor %}

  {% set totalPages = params.pages | length %}
  {% set position = "Page " + currentPageIndex + " of " + totalPages %}

  {# Calculate middle pages #}
  {% set middlePageCount = 5 %}
  {% set middlePagesEachSide = (middlePageCount - 1) / 2 %}

  {% if (currentPageIndex - middlePagesEachSide) <= 1 %}
      {% set middlePagesStart = 1 %}
      {% set middlePagesEnd = middlePageCount - 1 %}
  {% elif (currentPageIndex + middlePagesEachSide) >= totalPages %}
      {% set middlePagesStart = totalPages - middlePageCount + 1 %}
      {% set middlePagesEnd = totalPages %}
  {% else %}
      {% set middlePagesStart = currentPageIndex - middlePagesEachSide %}
      {% set middlePagesEnd = currentPageIndex + middlePagesEachSide %}
  {% endif %}


  <nav class="ons-pagination {{ params.classes }}{% if params.hideRangeIndicator is defined and params.hideRangeIndicator %} ons-pagination--no-indicator{% endif %}" arial-label="Pagination ({{ position }})">
      <div class="ons-pagination__position">{{ position }}</div>
      <ul class="ons-pagination__items">
          {% if currentPageIndex != 1 %}
              {% set prevPageIndex = currentPageIndex - 2 %}
              <li class="ons-pagination__item ons-pagination__item--previous">
                  <a href="{{ params.pages[prevPageIndex].url }}" class="ons-pagination__link" rel="prev" aria-label="Go to the previous page (Page {{ currentPageIndex - 1 }})">{{ params.previous }}</a>
              </li>
          {% endif %}
          {% if currentPageIndex > 3 %}
              {% set first = params.pages | first %}
              <li class="ons-pagination__item">
                  <a href="{{ first.url }}" class="ons-pagination__link" aria-label="Go to the first page (Page 1)">1</a>
              </li>
          {% endif %}
          {% if currentPageIndex > 4 %}
              <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
          {% endif %}
          {% for page in params.pages %}
              {% if loop.index >= middlePagesStart and loop.index <= middlePagesEnd %}
                  <li class="ons-pagination__item{% if page.current is defined and page.current == true %} ons-pagination__item--current{% endif %}">
                      <a href="{{ page.url }}" class="ons-pagination__link"
                          {%- if page.current -%}
                              aria-current="true" aria-label="Current page ({{ position }})"
                          {%- else -%}
                              aria-label="Go to page {{ loop.index }}"
                          {%- endif -%}
                          {%- if loop.index == currentPageIndex - 1 -%}
                              rel="prev"
                          {%- endif -%}
                          {%- if loop.index == currentPageIndex + 1 -%}
                              rel="next"
                          {%- endif -%}
                      >{{ loop.index }}</a>
                  </li>
              {% endif %}
          {% endfor %}
          {% if currentPageIndex < totalPages - 3 %}
              <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
          {% endif %}
          {% if currentPageIndex < totalPages - 2 %}
              {% set lastPage = params.pages | last %}
              <li class="ons-pagination__item">
                  <a href="{{ lastPage.url }}" class="ons-pagination__link" aria-label="Go to the last page (Page {{ totalPages }})">{{ totalPages }}</a>
              </li>
          {% endif %}
          {% if totalPages > 1 and totalPages != currentPageIndex %}
              <li class="ons-pagination__item ons-pagination__item--next">
                  <a href="{{ params.pages[currentPageIndex].url }}" class="ons-pagination__link" rel="next" aria-label="Go to the next page (Page {{ currentPageIndex + 1 }})">{{ params.next }}</a>
              </li>
          {% endif %}
      </ul>
  </nav>
{% endmacro %}
$pagination-item-padding: 0.5rem;
$pagination-item-width: 2.5rem;

.ons-pagination {
  $ctx: &;

  &__items {
    margin: 0 $pagination-item-padding * -1;
    padding: 0;
  }

  &__item {
    display: none;
    text-align: center;

    &--previous,
    &--next {
      display: inline-block;
    }

    @include mq(m) {
      &:not(&--previous) {
        display: inline-block;
      }
    }
  }

  &__item,
  &__link {
    height: $pagination-item-width;
    min-width: $pagination-item-width;
  }

  &__link {
    border-radius: 3px;
    display: block;
    padding: $pagination-item-padding;

    &:hover,
    &:focus {
      background: $color-grey-5;
    }
  }

  &__item--current &__link {
    background: $color-text-link-hover;
    color: $color-white;
    text-decoration: none;
  }

  &--no-indicator & {
    &__position {
      @include mq(m) {
        display: none;
      }
    }
  }
}

Long pagination (no range indicator)

The range indicator will be hidden on desktop, however it will still show on mobile as the page numbers don’t show.

<nav class="ons-pagination  ons-pagination--no-indicator" arial-label="Pagination (Page 7 of 35)">
  <div class="ons-pagination__position">Page 7 of 35</div>
  <ul class="ons-pagination__items">
    <li class="ons-pagination__item ons-pagination__item--previous">
      <a href="#page6" class="ons-pagination__link" rel="prev" aria-label="Go to the previous page (Page 6)">Previous</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#page1" class="ons-pagination__link" aria-label="Go to the first page (Page 1)">1</a>
    </li>
    <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
    <li class="ons-pagination__item">
      <a href="#page5" class="ons-pagination__link" aria-label="Go to page 5">5</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#page6" class="ons-pagination__link" aria-label="Go to page 6" rel="prev">6</a>
    </li>
    <li class="ons-pagination__item ons-pagination__item--current">
      <a href="#page7" class="ons-pagination__link" aria-current="true" aria-label="Current page (Page 7 of 35)">7</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#page8" class="ons-pagination__link" aria-label="Go to page 8" rel="next">8</a>
    </li>
    <li class="ons-pagination__item">
      <a href="#page9" class="ons-pagination__link" aria-label="Go to page 9">9</a>
    </li>
    <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
    <li class="ons-pagination__item">
      <a href="#page35" class="ons-pagination__link" aria-label="Go to the last page (Page 35)">35</a>
    </li>
    <li class="ons-pagination__item ons-pagination__item--next">
      <a href="#page8" class="ons-pagination__link" rel="next" aria-label="Go to the next page (Page 8)">Next</a>
    </li>
  </ul>
</nav>
{% from "components/pagination/_macro.njk" import onsPagination %}

{{
    onsPagination({
        "previous": "Previous",
        "next": "Next",
        "hideRangeIndicator": true,
        "pages": [
            {
                "url": "#page1"
            },
            {
                "url": "#page2"
            },
            {
                "url": "#page3"
            },
            {
                "url": "#page4"
            },
            {
                "url": "#page5"
            },
            {
                "url": "#page6"
            },
            {
                "url": "#page7",
                "current": true
            },
            {
                "url": "#page8"
            },
            {
                "url": "#page9"
            },
            {
                "url": "#page10"
            },
            {
                "url": "#page11"
            },
            {
                "url": "#page12"
            },
            {
                "url": "#page13"
            },
            {
                "url": "#page14"
            },
            {
                "url": "#page15"
            },
            {
                "url": "#page16"
            },
            {
                "url": "#page17"
            },
            {
                "url": "#page18"
            },
            {
                "url": "#page19"
            },
            {
                "url": "#page20"
            },
            {
                "url": "#page21"
            },
            {
                "url": "#page22"
            },
            {
                "url": "#page23"
            },
            {
                "url": "#page24"
            },
            {
                "url": "#page25"
            },
            {
                "url": "#page26"
            },
            {
                "url": "#page27"
            },
            {
                "url": "#page28"
            },
            {
                "url": "#page29"
            },
            {
                "url": "#page30"
            },
            {
                "url": "#page31"
            },
            {
                "url": "#page32"
            },
            {
                "url": "#page33"
            },
            {
                "url": "#page34"
            },
            {
                "url": "#page35"
            }
        ]
    })
}}
Name Type Required Description
pages Array true An array of all pages
previous string true Text for the previous button
next string true Text for the next button
classes string false Classes to add to the pagination
hideRangeIndicator boolean false When set to true will hide the range indicator on desktop

Page

Name Type Required Description
url string true URL for the page
current boolean false If this is the current page set to true
{% macro onsPagination(params) %}
  {% set currentPageIndex = "" %}
  {% for page in params.pages %}
      {% if page.current is defined and page.current %}
          {% set currentPageIndex = loop.index %}
      {% endif %}
  {% endfor %}

  {% set totalPages = params.pages | length %}
  {% set position = "Page " + currentPageIndex + " of " + totalPages %}

  {# Calculate middle pages #}
  {% set middlePageCount = 5 %}
  {% set middlePagesEachSide = (middlePageCount - 1) / 2 %}

  {% if (currentPageIndex - middlePagesEachSide) <= 1 %}
      {% set middlePagesStart = 1 %}
      {% set middlePagesEnd = middlePageCount - 1 %}
  {% elif (currentPageIndex + middlePagesEachSide) >= totalPages %}
      {% set middlePagesStart = totalPages - middlePageCount + 1 %}
      {% set middlePagesEnd = totalPages %}
  {% else %}
      {% set middlePagesStart = currentPageIndex - middlePagesEachSide %}
      {% set middlePagesEnd = currentPageIndex + middlePagesEachSide %}
  {% endif %}


  <nav class="ons-pagination {{ params.classes }}{% if params.hideRangeIndicator is defined and params.hideRangeIndicator %} ons-pagination--no-indicator{% endif %}" arial-label="Pagination ({{ position }})">
      <div class="ons-pagination__position">{{ position }}</div>
      <ul class="ons-pagination__items">
          {% if currentPageIndex != 1 %}
              {% set prevPageIndex = currentPageIndex - 2 %}
              <li class="ons-pagination__item ons-pagination__item--previous">
                  <a href="{{ params.pages[prevPageIndex].url }}" class="ons-pagination__link" rel="prev" aria-label="Go to the previous page (Page {{ currentPageIndex - 1 }})">{{ params.previous }}</a>
              </li>
          {% endif %}
          {% if currentPageIndex > 3 %}
              {% set first = params.pages | first %}
              <li class="ons-pagination__item">
                  <a href="{{ first.url }}" class="ons-pagination__link" aria-label="Go to the first page (Page 1)">1</a>
              </li>
          {% endif %}
          {% if currentPageIndex > 4 %}
              <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
          {% endif %}
          {% for page in params.pages %}
              {% if loop.index >= middlePagesStart and loop.index <= middlePagesEnd %}
                  <li class="ons-pagination__item{% if page.current is defined and page.current == true %} ons-pagination__item--current{% endif %}">
                      <a href="{{ page.url }}" class="ons-pagination__link"
                          {%- if page.current -%}
                              aria-current="true" aria-label="Current page ({{ position }})"
                          {%- else -%}
                              aria-label="Go to page {{ loop.index }}"
                          {%- endif -%}
                          {%- if loop.index == currentPageIndex - 1 -%}
                              rel="prev"
                          {%- endif -%}
                          {%- if loop.index == currentPageIndex + 1 -%}
                              rel="next"
                          {%- endif -%}
                      >{{ loop.index }}</a>
                  </li>
              {% endif %}
          {% endfor %}
          {% if currentPageIndex < totalPages - 3 %}
              <li class="ons-pagination__item ons-pageination__item--gap">&hellip;</li>
          {% endif %}
          {% if currentPageIndex < totalPages - 2 %}
              {% set lastPage = params.pages | last %}
              <li class="ons-pagination__item">
                  <a href="{{ lastPage.url }}" class="ons-pagination__link" aria-label="Go to the last page (Page {{ totalPages }})">{{ totalPages }}</a>
              </li>
          {% endif %}
          {% if totalPages > 1 and totalPages != currentPageIndex %}
              <li class="ons-pagination__item ons-pagination__item--next">
                  <a href="{{ params.pages[currentPageIndex].url }}" class="ons-pagination__link" rel="next" aria-label="Go to the next page (Page {{ currentPageIndex + 1 }})">{{ params.next }}</a>
              </li>
          {% endif %}
      </ul>
  </nav>
{% endmacro %}
$pagination-item-padding: 0.5rem;
$pagination-item-width: 2.5rem;

.ons-pagination {
  $ctx: &;

  &__items {
    margin: 0 $pagination-item-padding * -1;
    padding: 0;
  }

  &__item {
    display: none;
    text-align: center;

    &--previous,
    &--next {
      display: inline-block;
    }

    @include mq(m) {
      &:not(&--previous) {
        display: inline-block;
      }
    }
  }

  &__item,
  &__link {
    height: $pagination-item-width;
    min-width: $pagination-item-width;
  }

  &__link {
    border-radius: 3px;
    display: block;
    padding: $pagination-item-padding;

    &:hover,
    &:focus {
      background: $color-grey-5;
    }
  }

  &__item--current &__link {
    background: $color-text-link-hover;
    color: $color-white;
    text-decoration: none;
  }

  &--no-indicator & {
    &__position {
      @include mq(m) {
        display: none;
      }
    }
  }
}

Pager

<nav class="ons-content-pagination" aria-label="Guide pagination">
  <ul class="ons-content-pagination__list">
    <li class="ons-content-pagination__item">
      <a href="#" class="ons-content-pagination__link" rel="prev">
        <span class="ons-content-pagination__link-title">
          <svg class="ons-content-pagination__link-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
            <path d="M6.4,0.2L0.3,6.4c-0.2,0.2-0.2,0.4,0,0.6l6.2,5.8c0.2,0.2,0.4,0.1,0.6,0l0.8-0.9c0.2-0.2,0.1-0.4,0-0.6L3.9,7.6h12.5c0.2,0,0.4-0.2,0.4-0.4V6c0-0.2-0.2-0.4-0.4-0.4H3.8l4-4C8,1.5,8,1.2,7.9,1.1L7,0.2C6.9,0.1,6.6,0.1,6.4,0.2z" fill="currentColor"></path>
          </svg>
          <span class="ons-content-pagination__link-text">
            Previous
          </span>
        </span>
        <span class="ons-content-pagination__link-divider ons-u-vh">page in this guide is:</span>
        <span class="ons-content-pagination__link-label">Overview</span>
      </a>
    </li>
    <li class="ons-content-pagination__item">
      <a href="#" class="ons-content-pagination__link" rel="next">
        <span class="ons-content-pagination__link-title">
          <svg class="ons-content-pagination__link-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
            <path d="M10,0.2L9.1,1.1C9,1.2,9,1.5,9.1,1.6l4,4H0.6C0.4,5.6,0.2,5.8,0.2,6v1.2c0,0.2,0.2,0.4,0.4,0.4h12.5l-3.9,3.7c-0.2,0.2-0.2,0.4,0,0.6l0.8,0.9c0.2,0.2,0.4,0.2,0.6,0l6.2-5.8c0.2-0.2,0.2-0.4,0-0.6l-6.1-6.1C10.4,0.1,10.2,0.1,10,0.2z" fill="currentColor"></path>
          </svg>
          <span class="ons-content-pagination__link-text">
            Next
          </span>
        </span>
        <span class="ons-content-pagination__link-divider ons-u-vh">page in this guide is:</span>
        <span class="ons-content-pagination__link-label">Who should take part and why</span>
      </a>
    </li>
  </ul>
</nav>
{% from "components/content-pagination/_macro.njk" import onsContentPagination %}

{{-
  onsContentPagination({
    "contentPaginationItems": [
      {
        "rel": 'prev',
        "text": 'Previous',
        "url": '#',
        "label": 'Overview'
      },
      {
        "rel": 'next',
        "text": 'Next',
        "url": '#',
        "label": 'Who should take part and why'
      }
    ]
  })
}}
Name Type Required Description
ariaLabel string false The label added to the nav element (defaults to “Guide pagination”)
contentPaginationItems Array<contentPaginationItem> true Pagination items to render.

contentPaginationItem

Name Type Required Description
url string true The url for the link
rel string true Sets the rel attribute to on the link (‘next’ or ‘prev’). Determines the correct icon to render
text string true Text for the pagination link
bridgingText string true Sets the hidden text for screen readers to bridge the text and label. Defaults to “page in this guide is:”
label string false Title of the next/previous page
{% macro onsContentPagination(params) %}
  <nav class="ons-content-pagination" aria-label="{{ params.ariaLabel | default("Guide pagination") }}">
    <ul class="ons-content-pagination__list">
      {% for contentPaginationItem in params.contentPaginationItems %}
        <li class="ons-content-pagination__item">
          <a href="{{ contentPaginationItem.url }}" class="ons-content-pagination__link" rel="{{ contentPaginationItem.rel }}">
            <span class="ons-content-pagination__link-title">
              <svg class="ons-content-pagination__link-icon" xmlns="http://www.w3.org/2000/svg" height="13" width="17" viewBox="0 0 17 13">
                {% if contentPaginationItem.rel === 'prev' %}
                  <path d="M6.4,0.2L0.3,6.4c-0.2,0.2-0.2,0.4,0,0.6l6.2,5.8c0.2,0.2,0.4,0.1,0.6,0l0.8-0.9c0.2-0.2,0.1-0.4,0-0.6L3.9,7.6h12.5c0.2,0,0.4-0.2,0.4-0.4V6c0-0.2-0.2-0.4-0.4-0.4H3.8l4-4C8,1.5,8,1.2,7.9,1.1L7,0.2C6.9,0.1,6.6,0.1,6.4,0.2z" fill="currentColor"></path>
                {% else %}
                  <path d="M10,0.2L9.1,1.1C9,1.2,9,1.5,9.1,1.6l4,4H0.6C0.4,5.6,0.2,5.8,0.2,6v1.2c0,0.2,0.2,0.4,0.4,0.4h12.5l-3.9,3.7c-0.2,0.2-0.2,0.4,0,0.6l0.8,0.9c0.2,0.2,0.4,0.2,0.6,0l6.2-5.8c0.2-0.2,0.2-0.4,0-0.6l-6.1-6.1C10.4,0.1,10.2,0.1,10,0.2z" fill="currentColor"></path>
                {% endif %}
              </svg>
              <span class="ons-content-pagination__link-text">
                {{ contentPaginationItem.text }}
              </span>
            </span>
            <span class="ons-content-pagination__link-divider ons-u-vh">{{ contentPaginationItem.bridgingText | default("page in this guide is:") }}</span>
            <span class="ons-content-pagination__link-label">{{ contentPaginationItem.label }}</span>
          </a>
        </li>
      {% endfor %}
    </ul>
  </nav>
{% endmacro %}
.ons-content-pagination {
  display: block;
  margin: 1.5rem 0 2.5rem;

  &__list {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  &__item {
    margin: 0 0 1.5rem;
  }

  &__link {
    display: inline-block;
    text-decoration: none;

    &:hover {
      text-decoration: none;
      .ons-content-pagination__link-label {
        text-decoration: underline solid $color-text-link-hover 2px;
      }
    }

    &:focus {
      text-decoration: none;

      .ons-content-pagination__link-label {
        text-decoration: none;
      }
    }
  }

  &__link-icon {
    height: 0.9rem;
    width: 1.2rem;
  }

  &__link-title {
    display: block;
  }

  &__link-text {
    font-size: 1.2rem;
    font-weight: 700;
    line-height: normal;
    margin: 0 0 0 0.5rem;
  }

  &__link-label {
    display: inline-block;
    font-size: 0.9rem;
    margin: 0 0 0 2rem;
    text-decoration: underline;
  }
}

When to use this component

Pagination helps users to navigate between a large number of items that are distributed across multiple pages whenever there are too many items to show at once. This will be most useful in contexts such as table listings of data, search results, and directories.

What constitutes ‘too many’ for a user can be influenced by factors like:

  • amount of data in each entry (consider and test cognitive load for users)
  • system load times
  • screen space

When the number of pages exceeds the maximum display limit, ellipsis (…) are used to truncate the remaining pages.

How to use this component

If the pagination component sits inline with other content on the page, then the pagination should be left aligned.

Help improve this component

Let us know how we could improve this component or share your user research findings. Discuss the ‘Pagination’ component on GitHub