Skip to main content

User testing

Help us improve this service. Take part in a short online exercise

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 " aria-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-pagination__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-pagination__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<Page> true Settings for each page
previous string true Text label for the “Previous” link
next string true Text label for the “Next” link
classes string false Classes to add to the pagination HTML nav element
hideRangeIndicator boolean false Set to “true” to hide the range indicator on viewports ≥ 740px

Page

Name Type Required Description
url string true The URL for the HTML href attribute for the page link
current boolean false Set to “true” for the current loaded page link
{% 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 %}" aria-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-pagination__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-pagination__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;
    box-shadow: none;
    display: block;
    padding: $pagination-item-padding;

    &:focus {
      border-radius: 0;
    }
  }

  &__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" aria-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-pagination__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-pagination__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<Page> true Settings for each page
previous string true Text label for the “Previous” link
next string true Text label for the “Next” link
classes string false Classes to add to the pagination HTML nav element
hideRangeIndicator boolean false Set to “true” to hide the range indicator on viewports ≥ 740px

Page

Name Type Required Description
url string true The URL for the HTML href attribute for the page link
current boolean false Set to “true” for the current loaded page link
{% 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 %}" aria-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-pagination__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-pagination__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;
    box-shadow: none;
    display: block;
    padding: $pagination-item-padding;

    &:focus {
      border-radius: 0;
    }
  }

  &__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="#0" class="ons-content-pagination__link" rel="prev">
        <span class="ons-content-pagination__link-title">
          <svg class="ons-svg-icon ons-svg-icon--m" viewBox="0 0 17 13" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
            <path d="M6.4.2.3 6.4c-.2.2-.2.4 0 .6l6.2 5.8c.2.2.4.1.6 0l.8-.9c.2-.2.1-.4 0-.6l-4-3.7h12.5c.2 0 .4-.2.4-.4V6c0-.2-.2-.4-.4-.4H3.8l4-4c.2-.1.2-.4.1-.5L7 .2c-.1-.1-.4-.1-.6 0z" />
          </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="#0" class="ons-content-pagination__link" rel="next">
        <span class="ons-content-pagination__link-title">
          <svg class="ons-svg-icon ons-svg-icon--m" viewBox="0 0 17 13" xmlns="http://www.w3.org/2000/svg" focusable="false" fill="currentColor">
            <path d="m10 .2-.9.9c-.1.1-.1.4 0 .5l4 4H.6c-.2 0-.4.2-.4.4v1.2c0 .2.2.4.4.4h12.5l-3.9 3.7c-.2.2-.2.4 0 .6l.8.9c.2.2.4.2.6 0L16.8 7c.2-.2.2-.4 0-.6L10.7.3c-.3-.2-.5-.2-.7-.1z" />
          </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": '#0',
        "label": 'Overview'
      },
      {
        "rel": 'next',
        "text": 'Next',
        "url": '#0',
        "label": 'Who should take part and why'
      }
    ]
  })
}}
Name Type Required Description
ariaLabel string false The ARIA label added to the HTML nav landmark. Required when multiple navigation landmarks are on a page. Defaults to “Guide pagination”.
contentPaginationItems Array<contentPaginationItem> true Settings for the pagination items

contentPaginationItem

Name Type Required Description
url string true The URL for the pagination link
rel string true Sets the HTML rel attribute on the link to set the correct arrow icon. Set to “next” or “prev”.
text string true Text for the pagination link
bridgingText string false Sets the visually hidden text for screen readers to bridge the text and label. Defaults to “page in this guide is:”. For example, “Next page in this guide is: ‘Who should take part and why’.
label string true Title of the next or 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">
                {% if contentPaginationItem.rel == 'prev' %}
                  {% from "components/icons/_macro.njk" import onsIcon %}
                  {{
                      onsIcon({
                          "iconType": 'arrow-previous',
                          "iconSize": 'm'
                      })
                  }}
                {% else %}
                  {% from "components/icons/_macro.njk" import onsIcon %}
                  {{
                      onsIcon({
                          "iconType": 'arrow-next',
                          "iconSize": 'm'
                      })
                  }}
                {% endif %}
              <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-title {
    display: block;
  }

  &__link-text {
    @extend .ons-u-fs-m;

    margin: 0 0 0 0.5rem;
    vertical-align: middle;
  }

  &__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