September 16, 2022 Iryna Mosiiuk

Alpine.js with Shopify. Simple framework for using the reactive and declarative nature in your store.

Getting started with Alpine

Alpine is a secure, minimal frontend development framework for adding JavaScript behavior to HTML markups. It enables you to harness the reactive and declarative nature of popular frontend libraries and frameworks such as Angular, React, and Vue, at a much lower cost.
There is no build step and the library file size is about 4KB gzipped. Alpine is not meant to replace frameworks such as Vue and React; if you have a highly interactive single-page app, it’s better to stick to more powerful tools. It’s best used when your project requires only minimal JavaScript, such as when you only need one or two components, like dropdowns, sidebars, tabs, and image selection.
Now, let’s move on to installation steps and get our hands dirty with Alpine. 😉

Installation and basic use
Adding Alpine to a project is easy. You can either include it from a script tag through a CDN or import it as a module.

From script tag
Using a script tag is the easiest and most straightforward way to to add Alpine to your project. You just need to add the snippet below at the end of the <head> section of your HTML file:

<script defer src="https://unpkg.com/[email protected]/dist/cdn.min.js"></script>

Specifying the version as @3.x.x in the CDN will pull the latest version of Alpine v3. However, in production, it’s recommended to hardcode the latest version in the CDN link.

 

As a module
With this method, you first need to install Alpine via npm:
npm install alpinejs
Then, import Alpine into your bundle and initialize it:
import Alpine from 'alpinejs'

// optional
window.Alpine = Alpine
// initialize Alpine
Alpine.start()

 

Alpine.js with shopify

Alpine.js is easy integrated with liquid templates.
We can create components directly in files with extension liquid and transfer in this files all needed data from Shopify. Development of reactive components with dynamic content has never been so easy!
In our projects we often use Alpine.js to create such components like: gallery. popup, ajax cart, accordions, etc. Also it is widely used for main pages development such as cart page, product page, product listing page, header, footer etc.

Example of Alpine.js to develop mini cart on Shopify store

First of all you should create separate Apline component for mini cart. We use directive x-data:

<div class="alpine-ajax-cart" 
   x-data="alpineAjaxCart"
   x-show="show"
   @cart-update.window="open"
>

and transfer all data from alpineAjaxCart.js file, which is the function returning the object back

export default () => ({
show: false,
open() {
this.show = true;
},

close() {
this.show = false;
},

clearCart() {
fetch('/cart/clear.js', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
}).then((response) => {
if (response.ok) {
console.log('clear');
this.$dispatch('cart-update');
}

this.cartError = !response.ok;
});
},
});

Also it is needed to create Alpine store which is a global component to get data cart from any pages of your Shopify store. 

import Alpine from 'alpinejs';
import alpineAjaxCart from './components/alpineAjaxCart';
Alpine.data('alpineAjaxCart', alpineAjaxCart);

Alpine.store('cart', {
cartData: null,
getCartData() {
fetch('/cart.js').then((res) => res.json()).then((json) => {
this.cartData = json;
});
},
});


window.Alpine = Alpine;
Alpine.start();

Next we need to create event “cart-update” which will reply on changes in cart data.

<button x-data="{
   addToCart() {
const variantData = {
'id': {{ product.first_available_variant.id | json }},
'quantity': 1,
};

fetch('/cart/add.js', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-Requested-With':'XMLHttpRequest'
},

body: JSON.stringify(variantData),
}).then(response => {
if (response.ok) this.$dispatch('cart-update')
this.cartError = !response.ok
})
}
}" @click='addToCart'> Add to bag </button>

clearCart() {
fetch('/cart/clear.js', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},

}).then((response) => {
if (response.ok) {
console.log('clear');
this.$dispatch('cart-update');
}

this.cartError = !response.ok;
});
},

Event “cart-update” we should check globally and its better to do it in tag <body>:

 
<body
 x-data
 @cart-update="$store.cart.getCartData();"
 x-init="$store.cart.getCartData();"
>

 

Then we will get updated data in cart.

Now we will detailed review cod from section alpine-ajax-cart.liquid

<div class="alpine-ajax-cart" 
   x-data="alpineAjaxCart"
   x-show="show"
   @cart-update.window="open"
>

   <div class="alpine-ajax-cart__header">
       <h2>Alpine ajax cart</h2>
       <button class="alpine-ajax-cart__close" @click="close">X</button>
    </div>

   <template x-if="$store.cart.cartData?.item_count"> 
       <div class="alpine-ajax-cart__body">
           <template x-for="item in $store.cart.cartData.items" :key="item.key"> 
               <div class="alpine-ajax-cart__item">
                  <div class="alpine-ajax-cart__item-img">
                       <img :src="item.featured_image.url" :alt="item.featured_image.alt">
                    </div>

                   <div class="alpine-ajax-cart__item-info">
                       <h3 class="alpine-ajax-cart__item-title" x-text="item.product_title"></h3>
                       <p class="alpine-ajax-cart__item-price" x-text="`${item.price / 100}$`"></p>
                       <p class="alpine-ajax-cart__item-qty" x-text="item.quantity"></p>
                   </div>
               </div>
          </template>
       </div>
    </template>

   <template x-if="$store.cart.cartData?.item_count"> 
       <div class="alpine-ajax-cart__footer">
           <a href="/checkout">Checkout</a>
           <p x-text="`Total: ${$store.cart.cartData.total_price/100}$`"></p>
           <button @click="clearCart">Clear cart</button>
       </div>
    </template>

   <template x-if="$store.cart.cartData?.item_count == 0"> 
       <div class="alpine-ajax-cart__body">
           <h2>Your cart is empty</h2>
       </div>
   </template>
</div>

Using detective x-on (short note @) we can see events on elements such as: “clearCart”, “closeCart” etc.

Directive и x-for and x-if is used only for tag  <template>. And then we can show data in cycle or only if some conditions are applied. 

All data from Shopify cart API will be saved in our $store.cart.cartData. From it we can show product data in cart, total_price, item_count etc.

Major functionality of our alpine-ajax-cart is ready. Of course you can add other components and more complicared logic. You can contact Mgroup to get further instructions.

Conclusion

Alpine.js pretty good integrates with languages of liquid templates which allow us to ealy do complicated components for your store. Also Alpine.js is a framework which is quite easy to learn and much more easy than widely known Vue and React. For more detailed information please contact us to learn more or get proficient consultation. Here is also detail explanation from Alpine documentation.

In this tutorial, we covered how to use Alpine and built a sample mini cart component with the framework. Though it might not totally replace other frameworks, it can be used in combination with React or Vue to quickly prototype components without writing much JavaScript. To learn more about Alpine, be sure to check out the framework’s website.