
Pagination is a common method for displaying large sets of data in manageable chunks. However, “Load More” functionality provides a seamless and user-friendly experience, allowing users to fetch more products without reloading the page. In this blog post, we’ll explore how to implement a “Load More” button in Shopify using JavaScript and Liquid.
Why Use a “Load More” Button Instead of Pagination?
- Improved User Experience – Users can browse content smoothly without navigating through multiple pages.
- Faster Interaction – AJAX-based loading eliminates page reloads, making browsing quicker.
- Modern Design Trend – Many eCommerce websites prefer this method to enhance engagement.
<div class="h-[200px] bg-black">
<div class="max-w-7xl mx-auto flex items-end h-full">
<div class="p-6">
<h1 class="text-white text-2xl md:text-4xl">{{ collection.title }}</h1>
<a href="/" class="text-white text-lg md:text-2xl">Home</a>
</div>
</div>
</div>
<div id="ProductGridContainer">
{% paginate collection.products by section.settings.number_of_products_per_page %}
<div
class="max-w-7xl mx-auto p-2 py-10"
x-data="
{
sort: '{{ sort_by }}',
sorting(){
fetch('/collections/{{ collection.handle }}?sort_by=' +this.sort)
.then(response => response.text())
.then(data=>{
let newElement = document.createElement('div');
newElement.innerHTML = data;
let newHTML = newElement.querySelector('#ProductGridContainer').innerHTML;
document.querySelector('#ProductGridContainer').innerHTML = newHTML;
history.replaceState(null,null, '?sort_by='+ this.sort)
})
.catch(error => sonsole.log(error))
}
}
"
>
{% if section.settings.enable_sorting %}
<select
name=""
id=""
x-model="sort"
@change="sorting()"
class="py-3 px-4 border bg-gray-100 rounded-sm cursor-pointer mb-8"
>
{% for option in collection.sort_options %}
<option
value="{{ option.value }}"
{%- if option.valeu == sort_by -%}
selected
{%- endif -%}
>
{{ option.name }}
</option>
{% endfor %}
</select>
{% endif %}
<div
class="load-more"
x-data="
{
page: 1,
hasMoreProducts: true,
loading: false,
async loadMore(){
this.loading = true;
this.page++;
const response = await fetch(`{{ collection.url }}?page=${this.page}`);
const text = await response.text();
const html = new DOMParser().parseFromString(text,'text/html');
const newHTML = html.querySelectorAll('#product-grid > *');
if(newHTML.length > 0){
newHTML.forEach(product => document.querySelector('#product-grid').appendChild(product) )
}
totalPages = parseInt(document.getElementById('totalPages').value);
if(this.page >= totalPages){
this.hasMoreProducts = false;
}
this.loading = false;
}
}
"
>
<input type="hidden" id="totalPages" value="{{ paginate.pages }}">
{% render 'loader' %}
<div class="grid grid-cols-2 md:grid-cols-4 gap-4" id="product-grid">
{% for product in collection.products %}
{% render 'product-card', productCard: product %}
{% endfor %}
</div>
{% if collection.all_products_count > section.settings.number_of_products_per_page %}
<button
x-show="hasMoreProducts"
@click="loadMore()"
class="bg-black text-white w-64 p-3 rounded-md flex justify-center items-center mt-10 mx-auto"
>
Load More
</button>
{% endif %}
</div>
{% comment %} {% render 'pagination', pagination: paginate %} {% endcomment %}
</div>
{% endpaginate %}
</div>
{% schema %}
{
"name": "Collection Page",
"settings": [
{
"type": "number",
"id": "number_of_products_per_page",
"label": "Number of products per page",
"default": 8
},
{
"type": "checkbox",
"id": "enable_sorting",
"label": "Enable sorting",
"default": false
}
]
}
{% endschema %}