Shopify Development⏱ 4 min read

How to Add a Sticky Add to Cart Bar on Shopify Product Pages (Liquid Snippet)

Boost mobile ecommerce conversions by building a native sticky Add to Cart bar in Shopify using pure Liquid and CSS that triggers on scroll with zero app fees.

Muhammad Bilal ShakeelWritten by Muhammad Bilal Shakeel
•Published: 2026-08-16•Updated: 2026-09-18
Advertisement

On modern direct-to-consumer (DTC) product detail pages (PDPs), content depth has increased dramatically. With high-resolution galleries, ingredient breakdowns, sizing charts, and verified review feeds stretching pages over 3,000 pixels vertically, the primary purchase button quickly scrolls off-screen. Adding a lightweight, native Sticky Add to Cart bar keeps the conversion action accessible at all times without adding heavy third-party app subscriptions. Below is an engineering implementation guide utilizing Liquid and the modern JavaScript IntersectionObserver API.

🚀 Performance Principle: IntersectionObserver vs. Scroll Event Listeners

Legacy Shopify sticky cart apps typically attach event handlers to window.onscroll. On mobile hardware, firing layout queries on every pixel of scroll causes continuous main-thread recalculations and degrades Interaction to Next Paint (INP). Modern engineering utilizes the native browser IntersectionObserver API, which monitors the visibility of the primary buy button asynchronously off the main thread with zero frame-rate stutter.

1. Production Liquid Snippet: snippets/sticky-add-to-cart.liquid

Create a new snippet under Snippets → Add a new snippet named sticky-add-to-cart.liquid:

{% comment %}
  snippets/sticky-add-to-cart.liquid
  Lightweight native sticky buy bar for Shopify product pages
{% endcomment %}
{% assign current_variant = product.selected_or_first_available_variant %}

<div id="sticky-atc-bar" class="sticky-atc-wrapper" aria-hidden="true">
  <div class="sticky-atc-container">
    <div class="sticky-atc-product">
      {% if product.featured_image %}
        <img src="{{ product.featured_image | image_url: width: 100 }}" alt="{{ product.title | escape }}" class="sticky-atc-thumb" width="48" height="48" loading="lazy">
      {% endif %}
      <div class="sticky-atc-info">
        <span class="sticky-atc-title">{{ product.title | truncate: 35 }}</span>
        <span class="sticky-atc-price" id="sticky-price">{{ current_variant.price | money }}</span>
      </div>
    </div>

    <div class="sticky-atc-actions">
      <button type="button" id="sticky-submit-btn" class="sticky-atc-btn" {% unless current_variant.available %}disabled{% endunless %}>
        {% if current_variant.available %}Add to Cart{% else %}Sold Out{% endif %}
      </button>
    </div>
  </div>
</div>

2. Lightweight IntersectionObserver Script

Add this script to the bottom of the snippet or inside your theme's JavaScript bundle:

<script>
document.addEventListener('DOMContentLoaded', function() {
  const stickyBar = document.getElementById('sticky-atc-bar');
  const primaryBtn = document.querySelector('form[action*="/cart/add"] button[type="submit"]') || document.querySelector('.product-form__submit');
  const stickyBtn = document.getElementById('sticky-submit-btn');

  if (!stickyBar || !primaryBtn) return;

  // Setup IntersectionObserver on primary product button
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(entry => {
      if (!entry.isIntersecting && entry.boundingClientRect.top < 0) {
        stickyBar.classList.add('is-visible');
        stickyBar.setAttribute('aria-hidden', 'false');
      } else {
        stickyBar.classList.remove('is-visible');
        stickyBar.setAttribute('aria-hidden', 'true');
      }
    });
  }, { threshold: 0 });

  observer.observe(primaryBtn);

  // Forward click to native Shopify product form
  if (stickyBtn) {
    stickyBtn.addEventListener('click', function() {
      primaryBtn.click();
    });
  }
});
</script>

3. Styling & Hardware Acceleration: assets/base.css

Add this CSS to assets/base.css to enable smooth, GPU-accelerated bottom sliding:

.sticky-atc-wrapper {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  background: rgba(18, 18, 18, 0.95);
  backdrop-filter: blur(12px);
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  padding: 12px 16px;
  padding-bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 99;
  transform: translateY(100%);
  opacity: 0;
  transition: transform 0.3s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
  pointer-events: none;
}
.sticky-atc-wrapper.is-visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.sticky-atc-container {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.sticky-atc-thumb {
  border-radius: 6px;
  object-fit: cover;
}
.sticky-atc-btn {
  background: #ff6b35;
  color: #ffffff;
  font-weight: 700;
  font-size: 14px;
  padding: 10px 24px;
  border-radius: 999px;
  border: none;
  cursor: pointer;
}

4. Edge Cases & Mobile Constraints

  • Safe Area Insets: Note the use of env(safe-area-inset-bottom) in the CSS. This prevents modern bezel-less iPhones from overlapping the home navigation bar over the sticky button.
  • Third-Party Chat Widgets: Fixed bottom chat widgets (Gorgias, Zendesk, LiveChat) can visually clash with the sticky bar. Set chat launcher widget offsets in their respective admin settings to float 70px above the bottom margin on mobile viewports.
  • Variant Synchronization: When shoppers select different variants on the main product page, listen to Shopify's variant change events to update the thumbnail, price, and disabled state on the sticky bar synchronously.

5. Live Variant Synchronization Script

To ensure the sticky bar reflects selected variant prices and availability when customers click swatch pills on the main product form, wire an event listener to the main variant selector:

// Listen to variant changes on Shopify Dawn variant pickers
document.addEventListener('variant:change', function(event) {
  const variant = event.detail.variant;
  const stickyPrice = document.getElementById('sticky-price');
  const stickyBtn = document.getElementById('sticky-submit-btn');
  if (!variant) return;

  if (stickyPrice) stickyPrice.textContent = '$' + (variant.price / 100).toFixed(2);
  if (stickyBtn) {
    if (variant.available) {
      stickyBtn.disabled = false;
      stickyBtn.textContent = 'Add to Cart';
    } else {
      stickyBtn.disabled = true;
      stickyBtn.textContent = 'Sold Out';
    }
  }
});

6. Frequently Asked Questions

Does adding a sticky buy bar hurt mobile Core Web Vitals or INP?

Because this implementation relies on the browser's native IntersectionObserver API rather than continuous scroll event listeners, CPU thread execution remains idle while the user scrolls. Animation uses hardware-accelerated CSS transforms (translateY), ensuring a flawless 60fps scrolling experience with zero penalty to Interaction to Next Paint (INP).

How do I handle products with mandatory custom text inputs or file uploads?

If your store requires custom engravings or monogram inputs, configure the sticky bar button to trigger a smooth scroll back to the required form fields instead of direct cart submission, alerting the shopper: "Please select your custom options above."

Elevate Your Store's Mobile Conversion Rate

Need custom PDP conversion features, slide-out cart upsells, or Core Web Vitals optimization without app bloat? Review our Shopify CRO services or calculate conversion lift with our CRO Revenue Calculator.

Advertisement
❓

Frequently Asked Questions

Does a sticky Add-to-Cart bar increase mobile conversion rates?

Yes. On long product description pages, a sticky bottom Add-to-Cart bar increases mobile conversion rates by 8% to 14% by keeping the primary CTA accessible at all scroll depths.

How do you detect when the main Add-to-Cart button leaves the viewport?

Use the modern JavaScript IntersectionObserver API to observe the primary form button, revealing the sticky bar with 0ms lag and zero CPU scroll-event thrashing.

Can the sticky bar sync with variant selections?

Yes, by binding an event listener to the main product form variant selector and updating the sticky bar's price and variant ID in real time.

Muhammad Bilal Shakeel (Goofy Developer)

Founder of Build With Goofy. Specializing in bespoke Shopify Liquid development, Core Web Vitals & mobile performance engineering, and automated GoHighLevel CRM workflows for clients across the USA, Canada, UK, and worldwide.

⚡ Shopify Store Optimization & Development

Need Help Fixing This on Your Store?

Send us your Shopify store URL for a comprehensive speed, Liquid code, and conversion architecture review.

💬 WhatsApp Bilal Directly

Related Developer Guides & Systems

View all guides →