Creating an Accessible Pagination with Liquid

Shopify pagination

One of the key elements when building an online store is to create a pagination system. Pagination enables users to navigate through a series of pages in which content has been split up for design purposes, usability, faster loading, and so on. Pagination might not be the sexiest component of an online store, but it’s definitely one of the most important ones.

Grow your business with the Shopify Partner Program

Whether you offer marketing, customization, or web design and development services, the Shopify Partner Program will set you up for success. Join for free and access revenue share opportunities, tools to grow your business, and a passionate commerce community.

Sign up

What is pagination, and what can I paginate in a theme?

Pagination is an ordered numbering of pages, usually located at the top or bottom of a webpage. Pagination helps to split products, blog articles, and search results across multiple pages. Within Shopify it is a necessary part of theme design, as you are limited to 50 results per page in any forloop.

In its simplest form the paginate tag works with the for tag to split content into multiple web pages. It must wrap a for tag block that loops through an array.

{% paginate collection.products by 5 %}
  {% for product in collection.products %}
    <!--show product details here -->    
  {% endfor %}
  <!-- show pagination links here -->  
{% endpaginate %}

You might also like: Understanding hreflang Tags for Multilingual Stores.

Building an accessible pagination

My favorite tutorials show a full example of the outcome immediately, to save time and give context. For this article I think it’s best to see the full example upfront and walk you through the code and what makes this pagination accessible. How each of the elements of this example work together to create a functioning accessible pagination is explained below, so read on to understand how this was built. Here’s the full example:

View on GitHub

Paginate tags

For this code to work, it must appear within paginate tags. Within the paginate tags, you can access the paginateobject and create markup for your pagination to render properly.

In this example we’re paginating blog articles, so this code would appear on the blog.liquid template, or in a section template that was being included in the blog.liquid template.

You can set a “limit” or number of blog posts to show on one page with your pagination by specifying the by parameter. This parameter is followed by an integer between 1 and 50 that tells the paginate tag how many results it should output per page. For example, if I wanted to show 10 articles per page with my pagination, then I would change the example above to read:

{%- paginate blog.articles by 10 -%}

Using semantic markup

In the full example, you’ll notice that we’ve used a nav element and an <ol> element. The <nav> element specifies to the browser that this is a list of links enabling a user to navigate the website, and the <ol> specifies an ordered list. The reason why we use this type of list is because semantically the content, our pagination links, are a list of ordered items. They must fall in a particular sequence to make sense, and are therefore best represented in HTML with an ordered list. We can use CSS at the end of this tutorial to change the visual rendering of the pagination, but semantically this is the best fit.

Template Icon

ARIA roles and attributes

If you’ve never used ARIA (Accessible Rich Internet Applications) before, I encourage you to read up on them. In a nutshell, ARIA attributes help to make web content and web applications (especially those developed with JavaScript) more accessible to people with disabilities. ARIA attributes supplement HTML so that interactions commonly used in applications can easily be passed to assistive technologies, and help aid in that user experience.

In the main example, we’ve used the role attribute and set it to a type of navigation.

<nav role="navigation">

Additionally, to make sure that the arrows, « and », which are really only useful to a sighted user, aren’t read aloud by screen readers, we’ve added the attribute of aria-hidden set to true. This ensures that the arrows are available to a sighted user without negatively impacting the experience of someone using a screen reader.

<span aria-hidden="true">&laquo;</span>

And finally, we’ve also used the aria-current attribute set to page, to indicate to a screen reader that this is the active or current item within a container or set of related elements. We determine if the page we are on is the current page by using a check to see if part.title is equal to paginate.current_page, and in this case remove the link (which disables the output from being clicked on, as well as placing the aria-current attribute on the <li>.

{%- if part.title == paginate.current_page -%}
<li class="active" aria-current="page">
<span class="visuallyhidden">page</span> {{ part.title }}
{%- else -%}

Adding CSS

You’ve likely seen the visuallyhidden class used in themes before, or even if you’ve used Bootstrap or HTML5 Boilerplate. The visuallyhidden class is used to hide content that we don’t want seen visually in the browser, but that we want still to be available to screen readers and search engines. In this case, we’ve used the visuallyhidden class around the word “page” so that screen readers read out Previous page and Next page or Page one, and Page two, when going through our pagination links. However, what we display on the screen is simply, Previous, Next, 1, 2, etc.

.visuallyhidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
white-space: nowrap;

All these elements combine to help make this pagination fully accessible and screen reader friendly.

You might also like: 10 Technical SEO Tips to Get the Most from an Ecommerce Website.

Start building more accessible themes!

Accessibility shouldn’t be an afterthought, add on, or something done at the end of a project. Instead, we should try and build accessibility into everything we build from the start, and that includes themes and the components that make them up.

Full Example on GitHub

Note: The default_pagination filter

The default_pagination filter can be used to create a simple pagination, however in its current state the filter’s output is not fully accessible. It looks something like this:

{{ paginate | default_pagination }}

We’re currently in the process of rectifying this, but for now the above example is accessible and gives you the opportunity to customize the markup more granularly in a theme.


Grow your business with the Shopify Partner Program

Learn more