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">…</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">…</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"
}
]
})
}}
{% 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">…</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">…</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">…</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">…</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"
}
]
})
}}
{% 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">…</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">…</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'
}
]
})
}}
{% 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