Skip to documentation content

Output pagination for a collection of entities

All complete examples

Render Bootstrap pagination links for a paged collection using shared configuration inputs.

What this example teaches

  • Accept a collection and pagination configuration as template inputs
  • Build accessible Bootstrap pagination markup from collection.page and total_pages

View this pattern on the live demo site

Files

Reusable pagination controls for lists and search results.

Liquid
{% comment %}
	Displays pagination links using bootstrap classes

	Inputs:
		collection - the collection to iterate over
		page_param - the query parameter to use for pagination links
		pagination_size - 'sm' or 'lg' (optional)
		pagination_justify - 'start', 'center', or 'end'
		max_pagination_links - the maximum number of pagination links to show (including the current page). Odd numbers work best.
		hide_prev_and_next - true to hide the "Previous" and "Next" links
		hide_first_and_last - true to hide the "first" and "last" links
		disable_404_for_empty_collections - true to prevent returning a 404 response if there are no items in the collection past page 2 (ref: https://www.searchenginejournal.com/technical-seo/pagination/)
{% endcomment -%}
{%- var total_pages = collection.total_pages | at_least: 1 -%}
{%- var current_page = collection.page | default:1 -%}
{%- if current_page > total_pages -%}
	{%- comment %}Intentionally set the current page to the total pages plus one so that the previous page link will correctly point to the last page in the collection{% endcomment -%}
	{%- set current_page = total_pages | plus: 1 -%}
	{%- unless disable_404_for_empty_collections %}{% set_response_code 404 "No Results" %}{% endunless -%}
{% endif -%}
{%- if total_pages > 1 or current_page > 1 -%}
	{%- var page_param = page_param | default:'page' -%}
	{%- var max_pagination_links = max_pagination_links | default: 11 | to_int | at_least: 1 -%}
	{%- var back_page = current_page | minus:1 -%}
	{%- var next_page = current_page | plus:1 -%}
	{%- var first_page = 1 -%}
	{%- var last_page = total_pages -%}
	{%- if last_page > max_pagination_links -%}
		{%- var offset = max_pagination_links | divided_by: 2 | floor -%}
		{%- if current_page > offset -%}
			{%- set first_page = current_page | minus: offset -%}
		{%- endif -%}
		{%- set last_page = first_page | plus: max_pagination_links | minus: 1 -%}
		{%- if last_page > total_pages -%}
			{%- set last_page = total_pages -%}
			{%- set first_page = last_page | minus: max_pagination_links | plus: 1 -%}
		{%- endif -%}
	{%- endif -%}
	<nav aria-label="Pagination">
		<ul class="pagination flex-wrap{% if pagination_size == 'lg' or pagination_size == 'sm' %} pagination-{{pagination_size}}{% endif %}{% if pagination_justify == 'start' or pagination_justify == 'center' or pagination_justify == 'end' %} justify-content-{{pagination_justify}}{% endif %}">
			{%- unless hide_first_and_last -%}
				{%- if current_page > 1 -%}
					<li class="page-item"><a class="page-link font-monospace" href="{% query_param_link = &page_param:false -%}" aria-title="First Page"><span aria-hidden="true">&#9198;</span></a></li>
				{%- else -%}
					<li class="page-item disabled" aria-hidden="true"><span class="page-link font-monospace">&#9198;</span></li>
				{%- endif -%}
			{%- endunless -%}
			{%- unless hide_prev_and_next -%}
				{%- if back_page < 1 -%}
					<li class="page-item disabled" aria-hidden="true"><span class="page-link font-monospace">&#9204;</span></li>
				{%- else -%}
					{%- if back_page == 1 %}{% set back_page = false %}{% endif %}
					<li class="page-item"><a class="page-link font-monospace" href="{% query_param_link = &page_param:back_page -%}" aria-title="Previous Page"><span aria-hidden="true">&#9204;</span></a></li>
				{%- endif -%}
			{%- endunless -%}
			{%- for page_num in (first_page..last_page) -%}
				{%- if current_page == page_num -%}
					<li class="page-item active"><span class="page-link"><span class="visually-hidden">You're on page</span> {{page_num}}</span></li>
				{%- else -%}
					{%- var page_link = page_num %}{% if page_link == 1 %}{% set page_link = false %}{% endif -%}
					<li class="page-item"><a class="page-link" href="{%- query_param_link = &page_param:page_link -%}" aria-label="Page {{page_num}}">{{page_num}}</a></li>
				{%- endif -%}
			{%- endfor -%}
			{%- unless hide_prev_and_next -%}
				{%- if next_page > total_pages -%}
					<li class="page-item disabled" aria-hidden="true"><span class="page-link font-monospace">&#9205;</span></li>
				{%- else -%}
					<li class="page-item"><a class="page-link font-monospace" href="{% query_param_link = &page_param:next_page -%}" aria-title="Next Page"><span aria-hidden="true">&#9205;</span></a></li>
				{%- endif -%}
			{%- endunless -%}
			{%- unless hide_first_and_last -%}
				{%- if current_page < total_pages -%}
					<li class="page-item"><a class="page-link font-monospace" href="{% query_param_link = &page_param:total_pages -%}" aria-title="Last Page"><span aria-hidden="true">&#9197;</span></a></li>
				{%- else -%}
					<li class="page-item disabled" aria-hidden="true"><span class="page-link font-monospace">&#9197;</span></li>
				{%- endif -%}
			{%- endunless -%}
		</ul>
	</nav>
{%- endif %}