Pagination Navigation #
How to create a list of links to every paginated page on a pagination template.
Paginating over an Array #
Consider the following example paginating our testdata
array:
---
pagination:
data: testdata
size: 2
testdata:
- item1
- item2
- item3
- item4
- item5
- item6
---
{# pagination.items has the data for the current page #}
The above example would make three different output files from the template.
- Page 1 would have
pagination.items
set to['item1', 'item2']
. - Page 2 would have
pagination.items
set to['item3', 'item4']
. - Page 3 would have
pagination.items
set to['item5', 'item6']
.
But to create a series of links to each of these paginated output templates, we’ll want to use our pagination.pages
entries New in v0.10.0, an array of the pagination.items
for each page.
A good way to think about it:
pagination.items
is the chunk of data for the current page.pagination.pages
is the chunked page data for all of the pages.
Starter Example #
To create an accessible navigation structure, we want to do our research first!
- Web Accessibility Tutorials from the w3c Web Accessibility Initiative: Menu Structure
- MDN web docs:
<nav>
: The Navigation Section element - Scott O’Hara with an Accessible Breadcrumb Navigation Pattern
- Léonie Watson on Using the aria-current attribute.
Alright, you definitely read all of those right? 😇 Here’s some accessible code you definitely would have written yourself after reading those wonderful resources:
<nav aria-labelledby="my-pagination">
<h2 id="my-pagination">This is my Pagination</h2>
<ol>
{%- for pageEntry in pagination.pages %}
<li><a href="{{ pagination.hrefs[ loop.index0 ] }}"{% if page.url == pagination.hrefs[ loop.index0 ] %} aria-current="page"{% endif %}>Page {{ loop.index }}</a></li>
{%- endfor %}
</ol>
</nav>
pagination.pages
is New in v0.10.0. For previous versions, iterate overpagination.hrefs
(although you won’t have access to the paginated items to show data about the pages).
For our example, this code will output the following markup for our example (on the first page):
<nav aria-labelledby="my-pagination">
<h2 id="my-pagination">This is my Pagination</h2>
<ol>
<li><a href="/test/" aria-current="page">Page 1</a></li>
<li><a href="/test/1/">Page 2</a></li>
<li><a href="/test/2/">Page 3</a></li>
</ol>
</nav>
id
attribute used on your heading (id="my-pagination"
) is unique to your page!Accessing the Original Paginated Content #
Say you want to output something from the paginated data instead of bland Page 1, Page 2, etc.
links. For that we need to access the original data!
When Paginating Arrays #
testdata:
- item1
- item2
- item3
- item4
- item5
- item6
<!-- Don’t copy this code, it’s been simplified for clarity -->
{% for pageEntry in pagination.pages %}
<a href="{{ pagination.hrefs[ loop.index0 ] }}">Page {{ loop.index }}</a>
{% endfor %}
- When
size
is set to 2,pagination.pages
will look like:[['item1', 'item2'], ['item3', 'item4'], ['item5', 'item6']]
- Use
pageEntry[0]
andpageEntry[1]
to access the original content.
- Use
- When
size
is set to 1,pagination.pages
will be the same as the original data:['item1', 'item2', 'item3', 'item4', 'item5', 'item6']
- Use
pageEntry
to access the original content.
- Use
When Paginating Object Literals #
testdata:
key1: item1
key2: item2
key3: item3
key4: item4
key5: item5
key6: item6
<!-- Don’t copy this code, it’s been simplified for clarity -->
{% for pageKey in pagination.pages %}
<a href="{{ pagination.hrefs[ loop.index0 ] }}">Page {{ loop.index }}</a>
{% endfor %}
- When
size
is set to 2,pagination.pages
will look like:[['key1', 'key2'], ['key3', 'key4'], ['key5', 'key6']]
- Use
testdata[ pageKey[0] ]
andtestdata[ pageKey[1] ]
to access the original content.
- Use
- When
size
is set to 1,pagination.pages
will be the keys of the object:['key1', 'key2', 'key3', 'key4', 'key5', 'key6']
- Use
testdata[ pageKey ]
to access the original content.
- Use
Visually Style the Current Page Link #
You’ll probably also want to add some kind of visual styling to indicate that the user is on the current page. For this let’s use a light background-color
.
[aria-current] {
background-color: #eee;
}
font-weight
here make sure the change in text size for the current page doesn’t make your navigation shift around between pages! This is especially important if your navigation links are displayed side-by-side on the same line.Add Previous and Next Links #
Note that if the current page (page.url
) is the first or last in the set, we won’t output links.
<nav aria-labelledby="my-pagination">
<h2 id="my-pagination">This is my Pagination</h2>
<ol>
<li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Previous</a>{% else %}Previous{% endif %}</li>
{%- for pageEntry in pagination.pages %}
<li><a href="{{ pagination.hrefs[ loop.index0 ] }}"{% if page.url == pagination.hrefs[ loop.index0 ] %} aria-current="page"{% endif %}>Page {{ loop.index }}</a></li>
{%- endfor %}
<li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% else %}Next{% endif %}</li>
</ol>
</nav>
pagination.href.previous
andpagination.href.next
are New in v0.10.0. Usepagination.previousPageHref
orpagination.nextPageHref
in previous versions.
Add First and Last Links #
For clarity here, we’re omitting the previous and next links from the previous section. Note the code below to show the links only if pagination.href.first
and pagination.href.last
don’t match the current page.url
.
<nav aria-labelledby="my-pagination">
<h2 id="my-pagination">This is my Pagination</h2>
<ol>
<li>{% if page.url != pagination.href.first %}<a href="{{ pagination.href.first }}">First</a>{% else %}First{% endif %}</li>
{%- for pageEntry in pagination.pages %}
<li><a href="{{ pagination.hrefs[ loop.index0 ] }}"{% if page.url == pagination.hrefs[ loop.index0 ] %} aria-current="page"{% endif %}>Page {{ loop.index }}</a></li>
{%- endfor %}
<li>{% if page.url != pagination.href.last %}<a href="{{ pagination.href.last }}">Last</a>{% else %}Last{% endif %}</li>
</ol>
</nav>
pagination.href.first
andpagination.href.last
are New in v0.10.0. Usepagination.firstPageHref
orpagination.lastPageHref
in previous versions.
Put It All Together #
Here’s the final pagination navigation template code, pieced together:
<nav aria-labelledby="my-pagination">
<h2 id="my-pagination">This is my Pagination</h2>
<ol>
<li>{% if page.url != pagination.href.first %}<a href="{{ pagination.href.first }}">First</a>{% else %}First{% endif %}</li>
<li>{% if pagination.href.previous %}<a href="{{ pagination.href.previous }}">Previous</a>{% else %}Previous{% endif %}</li>
{%- for pageEntry in pagination.pages %}
<li><a href="{{ pagination.hrefs[ loop.index0 ] }}"{% if page.url == pagination.hrefs[ loop.index0 ] %} aria-current="page"{% endif %}>Page {{ loop.index }}</a></li>
{%- endfor %}
<li>{% if pagination.href.next %}<a href="{{ pagination.href.next }}">Next</a>{% else %}Next{% endif %}</li>
<li>{% if page.url != pagination.href.last %}<a href="{{ pagination.href.last }}">Last</a>{% else %}Last{% endif %}</li>
</ol>
</nav>
Alright, you’ve copied the above—but don’t leave yet—your work is not done (sorry)! You still need to:
- Change
my-pagination
to a betterid
attribute for your use case and update it inaria-labelledby
too. - Update the
This is my Pagination
text to make more sense for your use case. - Think about maybe changing the
<h2>
to better suit your document structure. - Add some CSS to highlight the current page in the navigation, visually.
role="navigation"
here, but it’s superfluous when using <nav>
.list-style-type: none
, read this article about VoiceOverAll of the above will output the following HTML for our example (on the first page of the set):
<nav aria-labelledby="my-pagination">
<h2 id="my-pagination">This is my Pagination</h2>
<ol>
<li>First</li>
<li>Previous</li>
<li><a href="/test-array/" aria-current="page">Page 1</a></li>
<li><a href="/test-array/1/">Page 2</a></li>
<li><a href="/test-array/2/">Page 3</a></li>
<li><a href="/test-array/1/">Next</a></li>
<li><a href="/test-array/2/">Last</a></li>
</ol>
</nav>