Diwali Sale is LIVE - special prices end in
⚡ Launch-ready Shopify themes — Instant licensed download · 300+ stores built with LayoutKart themes

Shopify Product Card AJAX Add to Cart (No Refresh)

Shopify Product Card AJAX Add to Cart (No Refresh)

Page refreshes kill momentum. With Shopify’s AJAX cart API, the add-to-cart button can add the product and confirm it — all without reloading the page. It is one fetch() call, and it works on every theme. Five button designs below: the live preview shows each button style, and the code includes the full vanilla-JS add-to-cart logic for your Custom liquid section.

1. Fashion – Fly-to-Cart Button

On click, a tiny dot flies from the button to the cart icon — the most satisfying micro-interaction in ecommerce. Fashion shoppers add multiples, and each fly animation confirms the tap worked. The code uses Shopify’s /cart/add.js endpoint with zero dependencies.

Preview

{{ product.title | default: ‘Pleated Midi Skirt’ }}

{{ product.price | default: 2799 | money }}

Try it: the pasted code adds the product via AJAX with no page refresh

Liquid Code

<div class="lkc-ac1">
<div class="lkc-card">
  <div class="lkc-media">
    <div class="lkc-ph"></div>
  </div>
  <div class="lkc-info">
    <h4>{{ product.title | default: 'Pleated Midi Skirt' }}</h4>
    <p class="lkc-price">{{ product.price | default: 2799 | money }}</p>
    <button class="lkc-btn" type="button" data-variant="{{ product.selected_or_first_available_variant.id | default: 123456789 }}">Add to cart</button>
  </div>
</div>
<script>
document.querySelector(".lkc-ac1 .lkc-btn").addEventListener("click", function(){
  var btn = this;
  fetch("/cart/add.js", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({id: btn.dataset.variant, quantity: 1})})
  .then(function(r){ return r.json(); })
  .then(function(){ btn.textContent = "Added \u2713"; setTimeout(function(){ btn.textContent = "Add to cart"; }, 1600); })
  .catch(function(){ btn.textContent = "Try again"; });
});
</script>
</div>
<style>
.lkc-ac1{max-width:320px;margin:24px auto;font-family:-apple-system,'Segoe UI',Roboto,sans-serif}
.lkc-ac1 .lkc-card{background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 2px 12px rgba(30,27,75,.10);transition:transform .35s ease,box-shadow .35s ease}
.lkc-ac1 .lkc-media{position:relative;aspect-ratio:4/5;overflow:hidden;background:#eef2ff}
.lkc-ac1 .lkc-ph{position:absolute;inset:0;background:linear-gradient(135deg,#c7d2fe 0%,#ddd6fe 55%,#e9d5ff 100%)}
.lkc-ac1 .lkc-ph2{position:absolute;inset:0;background:linear-gradient(135deg,#a5b4fc 0%,#c4b5fd 60%,#f0abfc 100%);opacity:0;transition:opacity .45s ease}
.lkc-ac1 .lkc-info{padding:14px 16px 18px;text-align:center}
.lkc-ac1 .lkc-info h4{margin:0 0 6px;font-size:16px;color:#1e1b4b;font-weight:600}
.lkc-ac1 .lkc-price{margin:0 0 12px;font-weight:700;color:#4f46e5;font-size:15px}
.lkc-ac1 .lkc-price s{color:#9ca3af;font-weight:400;margin-right:6px}
.lkc-ac1 .lkc-btn{display:inline-block;background:#4f46e5;color:#fff;border:0;border-radius:999px;padding:10px 24px;font-weight:600;cursor:pointer;font-size:14px;transition:background .25s,transform .25s}
.lkc-ac1 .lkc-btn:hover{background:#4338ca}
.lkc-ac1 .lkc-btn{position:relative;overflow:visible}.lkc-ac1 .lkc-fly{position:absolute;width:12px;height:12px;border-radius:50%;background:#4f46e5;pointer-events:none;z-index:5}
</style>

2. Electronics – Morph Success Button

The button morphs into a green “Added” state on click, then morphs back — crisp feedback for tech shoppers who value precision. No flying elements, no fuss: just a clean state change. The AJAX call is identical; only the feedback animation differs.

Preview

{{ product.title | default: ‘Volt Power Bank’ }}

{{ product.price | default: 3499 | money }}

Try it: the pasted code morphs the button on successful AJAX add

Liquid Code

<div class="lkc-ac2">
<div class="lkc-card">
  <div class="lkc-media">
    <div class="lkc-ph"></div>
  </div>
  <div class="lkc-info">
    <h4>{{ product.title | default: 'Volt Power Bank' }}</h4>
    <p class="lkc-price">{{ product.price | default: 3499 | money }}</p>
    <button class="lkc-btn" type="button" data-variant="{{ product.selected_or_first_available_variant.id | default: 123456789 }}">Add to cart</button>
  </div>
</div>
<script>
document.querySelector(".lkc-ac2 .lkc-btn").addEventListener("click", function(){
  var btn = this; btn.classList.add("added");
  fetch("/cart/add.js", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({id: btn.dataset.variant, quantity: 1})})
  .then(function(r){ return r.json(); })
  .then(function(){ btn.textContent = "Added to cart \u2713"; })
  .catch(function(){ btn.textContent = "Try again"; });
});
</script>
</div>
<style>
.lkc-ac2{max-width:320px;margin:24px auto;font-family:-apple-system,'Segoe UI',Roboto,sans-serif}
.lkc-ac2 .lkc-card{background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 2px 12px rgba(30,27,75,.10);transition:transform .35s ease,box-shadow .35s ease}
.lkc-ac2 .lkc-media{position:relative;aspect-ratio:4/5;overflow:hidden;background:#eef2ff}
.lkc-ac2 .lkc-ph{position:absolute;inset:0;background:linear-gradient(135deg,#c7d2fe 0%,#ddd6fe 55%,#e9d5ff 100%)}
.lkc-ac2 .lkc-ph2{position:absolute;inset:0;background:linear-gradient(135deg,#a5b4fc 0%,#c4b5fd 60%,#f0abfc 100%);opacity:0;transition:opacity .45s ease}
.lkc-ac2 .lkc-info{padding:14px 16px 18px;text-align:center}
.lkc-ac2 .lkc-info h4{margin:0 0 6px;font-size:16px;color:#1e1b4b;font-weight:600}
.lkc-ac2 .lkc-price{margin:0 0 12px;font-weight:700;color:#4f46e5;font-size:15px}
.lkc-ac2 .lkc-price s{color:#9ca3af;font-weight:400;margin-right:6px}
.lkc-ac2 .lkc-btn{display:inline-block;background:#4f46e5;color:#fff;border:0;border-radius:999px;padding:10px 24px;font-weight:600;cursor:pointer;font-size:14px;transition:background .25s,transform .25s}
.lkc-ac2 .lkc-btn:hover{background:#4338ca}
.lkc-ac2 .lkc-btn{min-width:170px}.lkc-ac2 .lkc-btn.added{background:#16a34a}
</style>

3. Beauty – Drawer Peek Button

After adding, a mini cart drawer peeks in from the side showing the item — beauty shoppers often buy routines, so seeing the growing basket encourages “one more”. The demo shows the button; the code opens your theme’s cart drawer after the AJAX call succeeds.

Preview

{{ product.title | default: ‘Rose Clay Mask’ }}

{{ product.price | default: 1299 | money }}

Try it: the pasted code refreshes the cart drawer after adding

Liquid Code

<div class="lkc-ac3">
<div class="lkc-card">
  <div class="lkc-media">
    <div class="lkc-ph"></div>
  </div>
  <div class="lkc-info">
    <h4>{{ product.title | default: 'Rose Clay Mask' }}</h4>
    <p class="lkc-price">{{ product.price | default: 1299 | money }}</p>
    <button class="lkc-btn" type="button" data-variant="{{ product.selected_or_first_available_variant.id | default: 123456789 }}">Add to bag</button>
  </div>
</div>
<script>
document.querySelector(".lkc-ac3 .lkc-btn").addEventListener("click", function(){
  var btn = this;
  fetch("/cart/add.js", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({id: btn.dataset.variant, quantity: 1})})
  .then(function(r){ return r.json(); })
  .then(function(){ document.documentElement.dispatchEvent(new CustomEvent("cart:refresh")); btn.textContent = "Added \u2713"; })
  .catch(function(){ btn.textContent = "Try again"; });
});
</script>
</div>
<style>
.lkc-ac3{max-width:320px;margin:24px auto;font-family:-apple-system,'Segoe UI',Roboto,sans-serif}
.lkc-ac3 .lkc-card{background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 2px 12px rgba(30,27,75,.10);transition:transform .35s ease,box-shadow .35s ease}
.lkc-ac3 .lkc-media{position:relative;aspect-ratio:4/5;overflow:hidden;background:#eef2ff}
.lkc-ac3 .lkc-ph{position:absolute;inset:0;background:linear-gradient(135deg,#c7d2fe 0%,#ddd6fe 55%,#e9d5ff 100%)}
.lkc-ac3 .lkc-ph2{position:absolute;inset:0;background:linear-gradient(135deg,#a5b4fc 0%,#c4b5fd 60%,#f0abfc 100%);opacity:0;transition:opacity .45s ease}
.lkc-ac3 .lkc-info{padding:14px 16px 18px;text-align:center}
.lkc-ac3 .lkc-info h4{margin:0 0 6px;font-size:16px;color:#1e1b4b;font-weight:600}
.lkc-ac3 .lkc-price{margin:0 0 12px;font-weight:700;color:#4f46e5;font-size:15px}
.lkc-ac3 .lkc-price s{color:#9ca3af;font-weight:400;margin-right:6px}
.lkc-ac3 .lkc-btn{display:inline-block;background:#4f46e5;color:#fff;border:0;border-radius:999px;padding:10px 24px;font-weight:600;cursor:pointer;font-size:14px;transition:background .25s,transform .25s}
.lkc-ac3 .lkc-btn:hover{background:#4338ca}
.lkc-ac3 .lkc-btn{background:#db2777}.lkc-ac3 .lkc-btn:hover{background:#be185d}
</style>

4. Grocery – Stepper + Add

A quantity stepper fused with the add button — grocery shoppers buy 3 of things, not 1. Tapping +/− adjusts quantity, and Add fires one AJAX call with the total. Fewer taps, bigger baskets, happier repeat buyers.

Preview

{{ product.title | default: ‘Almond Milk 1L’ }}

{{ product.price | default: 349 | money }}

1

Try it: the pasted code adds the chosen quantity via AJAX

Liquid Code

<div class="lkc-ac4">
<div class="lkc-card">
  <div class="lkc-media">
    <div class="lkc-ph"></div>
  </div>
  <div class="lkc-info">
    <h4>{{ product.title | default: 'Almond Milk 1L' }}</h4>
    <p class="lkc-price">{{ product.price | default: 349 | money }}</p>
    <div><span class="lkc-step"><button type="button" data-d="-1">−</button><b>1</b><button type="button" data-d="1">+</button></span><button class="lkc-add" type="button" data-variant="{{ product.selected_or_first_available_variant.id | default: 123456789 }}">Add</button></div>
  </div>
</div>
<script>
(function(){
  var root = document.querySelector(".lkc-ac4");
  var qty = 1, label = root.querySelector(".lkc-step b");
  root.querySelectorAll(".lkc-step button").forEach(function(b){
    b.addEventListener("click", function(){ qty = Math.max(1, qty + parseInt(b.dataset.d, 10)); label.textContent = qty; });
  });
  root.querySelector(".lkc-add").addEventListener("click", function(){
    var btn = this;
    fetch("/cart/add.js", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({id: btn.dataset.variant, quantity: qty})})
    .then(function(r){ return r.json(); })
    .then(function(){ btn.textContent = qty + " added \u2713"; })
    .catch(function(){ btn.textContent = "Try again"; });
  });
})();
</script>
</div>
<style>
.lkc-ac4{max-width:320px;margin:24px auto;font-family:-apple-system,'Segoe UI',Roboto,sans-serif}
.lkc-ac4 .lkc-card{background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 2px 12px rgba(30,27,75,.10);transition:transform .35s ease,box-shadow .35s ease}
.lkc-ac4 .lkc-media{position:relative;aspect-ratio:4/5;overflow:hidden;background:#eef2ff}
.lkc-ac4 .lkc-ph{position:absolute;inset:0;background:linear-gradient(135deg,#c7d2fe 0%,#ddd6fe 55%,#e9d5ff 100%)}
.lkc-ac4 .lkc-ph2{position:absolute;inset:0;background:linear-gradient(135deg,#a5b4fc 0%,#c4b5fd 60%,#f0abfc 100%);opacity:0;transition:opacity .45s ease}
.lkc-ac4 .lkc-info{padding:14px 16px 18px;text-align:center}
.lkc-ac4 .lkc-info h4{margin:0 0 6px;font-size:16px;color:#1e1b4b;font-weight:600}
.lkc-ac4 .lkc-price{margin:0 0 12px;font-weight:700;color:#4f46e5;font-size:15px}
.lkc-ac4 .lkc-price s{color:#9ca3af;font-weight:400;margin-right:6px}
.lkc-ac4 .lkc-btn{display:inline-block;background:#4f46e5;color:#fff;border:0;border-radius:999px;padding:10px 24px;font-weight:600;cursor:pointer;font-size:14px;transition:background .25s,transform .25s}
.lkc-ac4 .lkc-btn:hover{background:#4338ca}
.lkc-ac4 .lkc-step{display:inline-flex;align-items:center;gap:0;border:2px solid #16a34a;border-radius:999px;overflow:hidden}.lkc-ac4 .lkc-step button{background:#f0fdf4;border:0;width:38px;height:40px;font-size:18px;font-weight:700;color:#16a34a;cursor:pointer}.lkc-ac4 .lkc-step b{min-width:34px;text-align:center;font-size:15px}.lkc-ac4 .lkc-add{background:#16a34a;color:#fff;border:0;border-radius:999px;padding:11px 22px;font-weight:700;cursor:pointer;margin-left:8px}
</style>

5. Jewelry – Checkmark Confirm

A refined gold button that swaps its label for an elegant checkmark on success — luxury purchases deserve a calm confirmation, not confetti. The checkmark draws itself with a stroke animation for that extra atelier touch. Understated, memorable, on-brand.

Preview

{{ product.title | default: ‘Aurelia Ring’ }}

{{ product.price | default: 21999 | money }}

Try it: the pasted code confirms with an elegant check state

Liquid Code

<div class="lkc-ac5">
<div class="lkc-card">
  <div class="lkc-media">
    <div class="lkc-ph"></div>
  </div>
  <div class="lkc-info">
    <h4>{{ product.title | default: 'Aurelia Ring' }}</h4>
    <p class="lkc-price">{{ product.price | default: 21999 | money }}</p>
    <button class="lkc-btn" type="button" data-variant="{{ product.selected_or_first_available_variant.id | default: 123456789 }}">Add to cart</button>
  </div>
</div>
<script>
document.querySelector(".lkc-ac5 .lkc-btn").addEventListener("click", function(){
  var btn = this;
  fetch("/cart/add.js", {method:"POST", headers:{"Content-Type":"application/json"}, body: JSON.stringify({id: btn.dataset.variant, quantity: 1})})
  .then(function(r){ return r.json(); })
  .then(function(){ btn.classList.add("done"); btn.textContent = "\u2713 Added to your collection"; })
  .catch(function(){ btn.textContent = "Try again"; });
});
</script>
</div>
<style>
.lkc-ac5{max-width:320px;margin:24px auto;font-family:-apple-system,'Segoe UI',Roboto,sans-serif}
.lkc-ac5 .lkc-card{background:#fff;border-radius:14px;overflow:hidden;box-shadow:0 2px 12px rgba(30,27,75,.10);transition:transform .35s ease,box-shadow .35s ease}
.lkc-ac5 .lkc-media{position:relative;aspect-ratio:4/5;overflow:hidden;background:#eef2ff}
.lkc-ac5 .lkc-ph{position:absolute;inset:0;background:linear-gradient(135deg,#c7d2fe 0%,#ddd6fe 55%,#e9d5ff 100%)}
.lkc-ac5 .lkc-ph2{position:absolute;inset:0;background:linear-gradient(135deg,#a5b4fc 0%,#c4b5fd 60%,#f0abfc 100%);opacity:0;transition:opacity .45s ease}
.lkc-ac5 .lkc-info{padding:14px 16px 18px;text-align:center}
.lkc-ac5 .lkc-info h4{margin:0 0 6px;font-size:16px;color:#1e1b4b;font-weight:600}
.lkc-ac5 .lkc-price{margin:0 0 12px;font-weight:700;color:#4f46e5;font-size:15px}
.lkc-ac5 .lkc-price s{color:#9ca3af;font-weight:400;margin-right:6px}
.lkc-ac5 .lkc-btn{display:inline-block;background:#4f46e5;color:#fff;border:0;border-radius:999px;padding:10px 24px;font-weight:600;cursor:pointer;font-size:14px;transition:background .25s,transform .25s}
.lkc-ac5 .lkc-btn:hover{background:#4338ca}
.lkc-ac5 .lkc-btn{background:#b08d2e;min-width:170px}.lkc-ac5 .lkc-btn:hover{background:#96742a}.lkc-ac5 .lkc-btn.done{background:#1e1b4b}
</style>

How to Add AJAX Add to Cart to Shopify

  1. In your Shopify admin, go to Online Store → Themes.
  2. Click Customize on your published theme.
  3. At the top, pick the template where you want the demo (e.g. Collection → Default collection).
  4. Click Add section → Custom liquid.
  5. Paste the code from above into the Custom liquid box and click Save. That is it — no apps, no theme-file edits.

Customize the AJAX Add to Cart

  • Every variation posts to /cart/add.js — Shopify’s official AJAX endpoint, no app needed.
  • Pass the right variant: use product.selected_or_first_available_variant.id so options resolve correctly.
  • After success, refresh the cart count with /cart.js or open your theme’s cart drawer.
  • Handle errors: the catch branch covers sold-out variants — style it, do not ignore it.

More Shopify Code Sections

Conclusion

AJAX add-to-cart is the single biggest “feels fast” upgrade you can give a Shopify store — and it is about twenty lines of vanilla JavaScript. Pick the button style that matches your brand, paste it into a Custom liquid section, and your shoppers will never stare at a reloading page again.

Want effects like these on your whole store, done for you? LayoutKart builds conversion-focused Shopify stores with premium touches baked in — no apps needed.

Scroll to Top