How to Add a Sticky Add to Cart Bar on Shopify Product Pages
A sticky add to cart bar keeps the buy button visible after a shopper scrolls past your product form. On long product pages — the ones with size charts, ingredient lists, reviews, and FAQ blocks — that's often the difference between a sale and a bounce. This guide covers the no-app method using your theme's Liquid files, plus a no-code fallback if you'd rather not touch code.
What a Sticky Add to Cart Bar Does (and When It's Worth Adding)
A sticky add to cart bar is a fixed element that appears at the bottom (or top) of the viewport once the shopper scrolls past the original Add to Cart button. It typically contains the product title, price, variant selector or a link back to the variant picker, and a button that submits the same form as the main product page.
It's worth adding when:
- Your product pages are long. Pages with 1,500+ words of description, comparison tables, or dozens of reviews push the buy button far off-screen.
- You sell on mobile. On phones, the product form is often two or three swipes down. A bottom bar sits within thumb reach and reduces the scroll-back friction.
- You have multiple variants. A sticky bar that keeps the variant selector visible prevents shoppers from losing their selection context.
- Your conversion data shows scroll depth without clicks. If analytics show people reaching 75% of the page but not converting, the buy button placement is a likely culprit.
Skip it if your product pages are short, if you sell one-off or made-to-order items where a deliberate decision process matters, or if your theme already includes a sticky bar (Dawn, Craft, and several paid themes ship with one built in — check your theme settings under Product page before writing any code).
Before You Start: Theme Backups and Duplicating Your Product Template
Never edit a live theme's Liquid directly. Do this instead:
- Duplicate your theme. In Shopify admin, go to Online Store → Themes, click the three dots next to your live theme, and choose Duplicate. Work on the copy. Only publish it once you've tested everything.
- Duplicate the product template. Go to Online Store → Themes → Edit code. Under Templates, find
product.json(orproduct.liquidon older themes). Click Duplicate and rename the copy, e.g.product.sticky.json. - Assign the template to one product first. Open a single test product, scroll to Theme template in the right sidebar, and select your new template. This lets you test on one URL without affecting your whole catalog.
- Note your theme's naming conventions. In JSON templates, sections are referenced by filename. In Liquid templates, snippets are included with
{% render 'filename' %}. Match whatever your theme already does.
If your theme uses a section-based product page (most modern themes do), you'll add a new section file rather than editing the product template directly. That's cleaner and easier to remove later.
How to Add a Sticky Add to Cart Bar on Shopify Product Pages Without an App
The approach: create a new section that renders a hidden sticky bar, then use JavaScript to reveal it when the main product form scrolls out of view. The bar submits the existing product form, so variant selection, quantity, and line item properties all stay in sync automatically.
Steps:
- In Edit code, open the Sections folder and click Add a new section. Name it
sticky-add-to-cart. - Paste the code from the next section into the new file.
- Open your product template (
product.jsonorproduct.liquid) and add the section to the template's section list, or render it with{% section 'sticky-add-to-cart' %}if your theme uses Liquid templates. - Save, then preview the assigned test product.
The critical detail is form attribute on the button. HTML lets a button submit a form it isn't nested inside, as long as the button's form attribute matches the form's id. Shopify's product form has a predictable ID in most themes (product-form-{{ section.id }} in Dawn-based themes, AddToCartForm in many older ones). Check your theme's product-form.liquid snippet or main product section to confirm the exact ID, and update the snippet below to match.
The Code Snippet: HTML, CSS, and JavaScript for Your Sticky Bar
{%- assign current_variant = product.selected_or_first_available_variant -%}
<div
id="sticky-atc-{{ section.id }}"
class="sticky-atc"
data-sticky-atc
data-form-id="product-form-{{ section.id }}"
aria-hidden="true"
>
<div class="sticky-atc__inner">
<div class="sticky-atc__info">
<span class="sticky-atc__title">{{ product.title | escape }}</span>
<span class="sticky-atc__price">{{ current_variant.price | money }}</span>
</div>
<button
type="submit"
form="product-form-{{ section.id }}"
name="add"
class="sticky-atc__button"
{% unless current_variant.available %}disabled{% endunless %}
>
{% if current_variant.available %}Add to cart{% else %}Sold out{% endif %}
</button>
</div>
</div>
{% style %}
.sticky-atc {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 20;
background: #fff;
border-top: 1px solid rgba(0,0,0,0.1);
transform: translateY(100%);
transition: transform 0.25s ease;
padding: 10px 16px;
padding-bottom: calc(10px + env(safe-area-inset-bottom));
}
.sticky-atc.is-visible {
transform: translateY(0);
}
.sticky-atc__inner {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
max-width: 1200px;
margin: 0 auto;
}
.sticky-atc__title {
display: block;
font-size: 14px;
font-weight: 600;
}
.sticky-atc__price {
font-size: 13px;
opacity: 0.75;
}
.sticky-atc__button {
flex: 0 0 auto;
padding: 12px 20px;
border: 0;
border-radius: 6px;
background: #111;
color: #fff;
font-size: 14px;
font-weight: 600;
cursor: pointer;
}
.sticky-atc__button[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
@media (max-width: 749px) {
.sticky-atc__title { font-size: 13px; }
}
{% endstyle %}
<script>
(function () {
var bar = document.querySelector('[data-sticky-atc]');
if (!bar) return;
var formId = bar.getAttribute('data-form-id');
var form = document.getElementById(formId);
if (!form) return;
var trigger = form.querySelector('[type="submit"]');
if (!trigger) return;
var observer = new IntersectionObserver(
function (entries) {
entries.forEach(function (entry) {
var past = !entry.isIntersecting && entry.boundingClientRect.top < 0;
bar.classList.toggle('is-visible', past);
bar.setAttribute('aria-hidden', past ? 'false' : 'true');
});
},
{ threshold: 0 }
);
observer.observe(trigger);
})();
</script>
Two things to verify before publishing: the data-form-id value matches your theme's actual form ID, and the price updates when a shopper changes variants. On most themes the price in the bar will be stale after a variant change unless you hook into the theme's variant-change event. If your theme fires one (Dawn-based themes publish a variant:change event on the document), listen for it and update .sticky-atc__price with the new variant's price.
Testing Your Sticky Bar on Mobile and Desktop
Run through this checklist on a duplicated theme before publishing:
- Scroll behavior. The bar should appear only after the main Add to Cart button leaves the viewport, and disappear when you scroll back up.
- Variant sync. Change the variant in the main form, then tap the sticky button. The correct variant should land in the cart.
- Sold-out state. Set a variant to zero inventory and confirm the button disables or reads "Sold out."
- Mobile safe area. On iPhones, the bar should sit above the home indicator, not behind it. The
env(safe-area-inset-bottom)padding handles this, but test on a real device. - Cart drawer or page. If your theme uses a cart drawer, confirm the sticky button triggers it the same way the main button does.
- Other sticky elements. Chat widgets, cookie banners, and back-to-top buttons can overlap. Adjust
z-indexor bottom offset as needed. - Accessibility. Tab to the sticky button with a keyboard and confirm focus is visible. Screen readers should not announce the bar while it's hidden — the
aria-hiddentoggle handles this.
Test on at least one iOS device, one Android device, and desktop Chrome and Safari. Browser dev tools' device emulation misses safe-area and scroll momentum behavior.
No-Code Alternative: A Cheaper App If You'd Rather Not Touch Liquid
If editing Liquid feels risky or you don't want to maintain the snippet when your theme updates, a dedicated app is the pragmatic choice. Several Shopify apps in the conversion-optimization category offer sticky add to cart bars as a core feature, including Releasit, Essential Add to Cart, and Sticky Add to Cart by various developers. Most install in a few clicks, let you style the bar from the theme editor, and handle variant syncing automatically.
What to check before installing:
- Does it support your theme? Most list supported themes on their App Store page.
- Does it sync variants and quantity? This is the most common failure point.
- Does it slow your page? Check the app's impact on your Lighthouse score after installing.
- What's the pricing model? Many are free with a paid tier; check current pricing on the App Store listing rather than relying on third-party reviews.
- Can you remove it cleanly? Apps that inject code into your theme can leave residue after uninstall. Prefer ones that load via app embed blocks.
For a single-store merchant, the app route usually costs less time than maintaining a custom snippet — but the snippet gives you full control over styling and zero monthly cost.
Common Issues and Quick Fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Bar never appears | Form ID in data-form-id doesn't match your theme |
Inspect the product form in dev tools and copy the exact id |
| Button adds wrong variant | Sticky button submits a stale form or a separate form | Ensure the button's form attribute points to the live product form |
| Bar covers footer content | Fixed positioning with no body padding | Add padding-bottom to body equal to the bar height when visible |
| Price doesn't update on variant change | No listener for the theme's variant-change event | Subscribe to variant:change and update the price node |
| Bar appears immediately on load | IntersectionObserver targeting the wrong element | Observe the main submit button, not the form container |
| Overlaps chat widget | Competing z-index values |
Lower the bar's z-index or raise the widget's bottom offset |
Conclusion
A sticky add to cart bar is one of the highest-leverage changes you can make to a long product page, and the no-app version is a single section file plus about 60 lines of CSS and JavaScript. Duplicate your theme, test on a single product template, and verify variant syncing before you publish. If maintaining Liquid isn't your thing, a reputable app gets you the same result in minutes — just check current pricing and theme compatibility first.
FAQ
Will a sticky bar hurt my page speed? The snippet above adds roughly 2KB of CSS and JavaScript, which is negligible. Apps vary — check your Lighthouse score before and after installing, and prefer apps that load via theme app extensions rather than injecting code into your theme files.
Does this work with Shopify's new themes like Dawn?
Yes. Dawn and themes built on the same architecture use predictable form IDs and fire a variant:change event, which makes the snippet easier to wire up. You'll need to confirm the form ID matches what your theme generates.
Can I show the bar only on mobile?
Yes. Wrap the .sticky-atc styles in a @media (max-width: 749px) block, or add a display condition in the section settings. Many merchants show it on all devices since desktop shoppers scroll long pages too — test both and compare conversion rates in your Shopify analytics.