Sticky Add to Cart

Sticky add to cart bar that appears on scroll with variant selector.

A sticky add to cart bar that slides up when scrolling down past the main add to cart button. Includes variant selector, price display, and smooth animations.
sticky-add-to-cart.liquidliquid
{% comment %} Sticky Add to Cart - snippets/sticky-add-to-cart.liquid {% endcomment %}
<div class="sticky-atc" data-sticky-atc>
  <div class="sticky-atc__container">
    <div class="sticky-atc__product">
      <img src="{{ product.featured_image | img_url: '80x' }}" 
           alt="{{ product.title }}" 
           class="sticky-atc__image">
      <div class="sticky-atc__info">
        <h3 class="sticky-atc__title">{{ product.title }}</h3>
        <div class="sticky-atc__price">
          <span class="price">{{ product.selected_or_first_available_variant.price | money }}</span>
          {% if product.selected_or_first_available_variant.compare_at_price > product.selected_or_first_available_variant.price %}
            <span class="compare-price">{{ product.selected_or_first_available_variant.compare_at_price | money }}</span>
          {% endif %}
        </div>
      </div>
    </div>

    <div class="sticky-atc__actions">
      {% if product.has_only_default_variant %}
        <button type="button" 
                class="sticky-atc__btn"
                data-add-to-cart>
          Add to Cart
        </button>
      {% else %}
        <select class="sticky-atc__variant" data-variant-select>
          {% for variant in product.variants %}
            <option value="{{ variant.id }}" 
                    {% if variant.available == false %}disabled{% endif %}>
              {{ variant.title }} - {{ variant.price | money }}
            </option>
          {% endfor %}
        </select>
        <button type="button" 
                class="sticky-atc__btn"
                data-add-to-cart>
          Add to Cart
        </button>
      {% endif %}
    </div>
  </div>
</div>

<style>
.sticky-atc {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: white;
  box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);
  transform: translateY(100%);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 100;
  border-top: 1px solid #e5e5e5;
}

.sticky-atc.visible {
  transform: translateY(0);
}

.sticky-atc__container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 16px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.sticky-atc__product {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: 1;
}

.sticky-atc__image {
  width: 60px;
  height: 60px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid #e5e5e5;
}

.sticky-atc__info {
  flex: 1;
}

.sticky-atc__title {
  font-size: 16px;
  font-weight: 600;
  margin: 0 0 4px;
  color: #000;
}

.sticky-atc__price {
  display: flex;
  align-items: center;
  gap: 8px;
}

.sticky-atc__price .price {
  font-size: 18px;
  font-weight: 700;
  color: #000;
}

.sticky-atc__price .compare-price {
  font-size: 14px;
  color: #999;
  text-decoration: line-through;
}

.sticky-atc__actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.sticky-atc__variant {
  padding: 12px 16px;
  border: 1px solid #e5e5e5;
  border-radius: 8px;
  font-size: 14px;
  min-width: 200px;
}

.sticky-atc__btn {
  padding: 14px 32px;
  background: #000;
  color: white;
  border: none;
  border-radius: 8px;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s;
  white-space: nowrap;
}

.sticky-atc__btn:hover {
  background: #333;
  transform: translateY(-2px);
}

@media (max-width: 768px) {
  .sticky-atc__container {
    flex-direction: column;
    gap: 12px;
  }
  
  .sticky-atc__actions {
    width: 100%;
  }
  
  .sticky-atc__variant,
  .sticky-atc__btn {
    flex: 1;
  }
}
</style>

<script>
document.addEventListener('DOMContentLoaded', () => {
  const stickyBar = document.querySelector('[data-sticky-atc]');
  const addToCartBtn = stickyBar.querySelector('[data-add-to-cart]');
  const variantSelect = stickyBar.querySelector('[data-variant-select]');
  
  let lastScroll = 0;
  const threshold = 500;

  window.addEventListener('scroll', () => {
    const currentScroll = window.pageYOffset;
    
    if (currentScroll > threshold && currentScroll > lastScroll) {
      stickyBar.classList.add('visible');
    } else if (currentScroll < lastScroll) {
      stickyBar.classList.remove('visible');
    }
    
    lastScroll = currentScroll;
  });

  addToCartBtn.addEventListener('click', async () => {
    const variantId = variantSelect ? variantSelect.value : addToCartBtn.dataset.variantId;
    
    try {
      const response = await fetch('/cart/add.js', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ id: variantId, quantity: 1 })
      });
      
      if (response.ok) {
        window.location.href = '/cart';
      }
    } catch (error) {
      console.error('Error adding to cart:', error);
    }
  });
});
</script>

Usage

{% render 'sticky-add-to-cart', product: product %} on product pages

Installation

Add to snippets/sticky-add-to-cart.liquid

Let’s Build Something You’ll Be Proud Of

No fluff. Just thoughtful design and reliable development.

Work with me
Average response time: within 24 hours