This custom code is completely free to use, but please note it does not include 1-on-1 technical support. If you need a bespoke, done-for-you solution to customize your Shopify store, my team is here to help! Head to my channel homepage and use the link in the trailer to reach out.
{% comment %}
<!-- Designed by ONHOW Studio YouTube Channel - Anas El Medlaoui -->
{% endcomment %}
<style>
.onhow-studio-upsell-widget {
margin: 2rem 0;
padding: 1rem 0;
font-family: inherit;
width: 100%;
box-sizing: border-box;
}
.onhow-studio-upsell-heading {
font-size: calc(var(--font-heading-scale, 1) * 1.2rem);
margin-bottom: 1.25rem;
font-weight: 600;
color: inherit;
letter-spacing: inherit;
}
.onhow-studio-upsell-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 1.25rem;
}
.onhow-studio-upsell-card {
display: flex;
flex-direction: column;
border: 1px solid rgba(var(--color-foreground, 0, 0, 0), 0.08);
border-radius: min(var(--border-radius, 8px), 8px);
overflow: hidden;
background: rgb(var(--color-background, 255, 255, 255));
transition: box-shadow 0.2s ease, transform 0.2s ease;
height: 100%;
}
.onhow-studio-upsell-card:hover {
box-shadow: 0 4px 12px rgba(var(--color-foreground, 0, 0, 0), 0.05);
}
.onhow-studio-upsell-image-link {
display: block;
position: relative;
width: 100%;
padding-top: 125%;
background-color: rgba(var(--color-foreground, 0, 0, 0), 0.03);
overflow: hidden;
}
.onhow-studio-upsell-image,
.onhow-studio-upsell-placeholder {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.onhow-studio-upsell-card:hover .onhow-studio-upsell-image {
transform: scale(1.03);
}
.onhow-studio-upsell-placeholder {
fill: rgba(var(--color-foreground, 0, 0, 0), 0.2);
}
.onhow-studio-upsell-info {
padding: 1rem;
display: flex;
flex-direction: column;
flex-grow: 1;
}
.onhow-studio-upsell-title {
font-size: 0.95rem;
color: inherit;
text-decoration: none;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 0.5rem;
line-height: 1.3;
font-weight: 500;
}
.onhow-studio-upsell-price {
font-size: 0.9rem;
margin-bottom: 1rem;
font-weight: 500;
color: inherit;
}
.onhow-studio-upsell-price-compare {
color: rgba(var(--color-foreground, 0, 0, 0), 0.6);
font-size: 0.8rem;
margin-left: 0.4rem;
}
.onhow-studio-upsell-form {
margin-top: auto;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.onhow-studio-upsell-variant-select {
width: 100%;
padding: 0.5rem;
border: 1px solid rgba(var(--color-foreground, 0, 0, 0), 0.1);
border-radius: min(var(--border-radius, 4px), 4px);
background: transparent;
font-size: 0.85rem;
font-family: inherit;
color: inherit;
appearance: auto;
cursor: pointer;
}
.onhow-studio-upsell-button {
width: 100%;
padding: 0.6rem;
background-color: rgb(var(--color-button, 0, 0, 0));
color: rgb(var(--color-button-text, 255, 255, 255));
border: none;
border-radius: min(var(--border-radius, 4px), 4px);
cursor: pointer;
font-weight: 600;
font-size: 0.85rem;
text-align: center;
text-transform: inherit;
letter-spacing: inherit;
transition: opacity 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
font-family: inherit;
}
.onhow-studio-upsell-button:hover:not(:disabled) {
opacity: 0.85;
}
.onhow-studio-upsell-button:disabled {
background-color: rgba(var(--color-foreground, 0, 0, 0), 0.1);
color: rgba(var(--color-foreground, 0, 0, 0), 0.4);
cursor: not-allowed;
}
@media screen and (max-width: 768px) {
.onhow-studio-upsell-grid {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
padding-bottom: 1rem;
-webkit-overflow-scrolling: touch;
margin-right: -1.5rem;
padding-right: 1.5rem;
}
.onhow-studio-upsell-grid::-webkit-scrollbar {
height: 4px;
}
.onhow-studio-upsell-grid::-webkit-scrollbar-thumb {
background-color: rgba(var(--color-foreground, 0, 0, 0), 0.15);
border-radius: 4px;
}
.onhow-studio-upsell-card {
flex: 0 0 160px;
scroll-snap-align: start;
}
}
</style>
{% if product.metafields.custom.upsell_products and product.metafields.custom.upsell_products.value != blank %}
<div class="onhow-studio-upsell-widget">
<h3 class="onhow-studio-upsell-heading">Pairs well with</h3>
<div class="onhow-studio-upsell-grid">
{% for upsell_product in product.metafields.custom.upsell_products.value %}
{% if upsell_product.available %}
<div class="onhow-studio-upsell-card">
<a href="{{ upsell_product.url }}" class="onhow-studio-upsell-image-link">
{% if upsell_product.featured_image %}
<img
src="{{ upsell_product.featured_image | image_url: width: 400 }}"
alt="{{ upsell_product.title | escape }}"
class="onhow-studio-upsell-image"
loading="lazy"
>
{% else %}
{{ 'product-1' | placeholder_svg_tag: 'onhow-studio-upsell-placeholder' }}
{% endif %}
</a>
<div class="onhow-studio-upsell-info">
<a href="{{ upsell_product.url }}" class="onhow-studio-upsell-title">{{ upsell_product.title }}</a>
<div class="onhow-studio-upsell-price">
{% if upsell_product.compare_at_price > upsell_product.price %}
<span>{{ upsell_product.price | money }}</span>
<s class="onhow-studio-upsell-price-compare">{{ upsell_product.compare_at_price | money }}</s>
{% else %}
<span>{{ upsell_product.price | money }}</span>
{% endif %}
</div>
<form class="onhow-studio-upsell-form">
{% if upsell_product.has_only_default_variant %}
<input type="hidden" name="id" value="{{ upsell_product.selected_or_first_available_variant.id }}">
{% else %}
<select name="id" class="onhow-studio-upsell-variant-select">
{% for variant in upsell_product.variants %}
<option
value="{{ variant.id }}"
{% unless variant.available %}disabled{% endunless %}
{% if variant == upsell_product.selected_or_first_available_variant %}selected{% endif %}
>
{{ variant.title }} — {{ variant.price | money }}
</option>
{% endfor %}
</select>
{% endif %}
<button
type="submit"
class="onhow-studio-upsell-button"
{% unless upsell_product.selected_or_first_available_variant.available %}disabled{% endunless %}
>
{% if upsell_product.selected_or_first_available_variant.available %}
Add to cart
{% else %}
Sold out
{% endif %}
</button>
</form>
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
<script>
(function () {
document.addEventListener('change', function (e) {
if (!e.target.classList.contains('onhow-studio-upsell-variant-select')) return;
const form = e.target.closest('.onhow-studio-upsell-form');
const btn = form && form.querySelector('.onhow-studio-upsell-button');
if (!btn) return;
const selected = e.target.options[e.target.selectedIndex];
btn.disabled = selected.disabled;
btn.textContent = selected.disabled ? 'Sold out' : 'Add to cart';
});
document.addEventListener('submit', function (e) {
if (!e.target.classList.contains('onhow-studio-upsell-form')) return;
e.preventDefault();
const form = e.target;
const btn = form.querySelector('.onhow-studio-upsell-button');
const originalText = btn.innerText;
const variantId = Number(new FormData(form).get('id'));
const sectionId = (document.querySelector('cart-items-component[data-drawer]') || {}).dataset?.sectionId;
btn.disabled = true;
btn.innerText = 'Adding...';
const payload = { items: [{ id: variantId, quantity: 1 }] };
if (sectionId) payload.sections = sectionId;
fetch(
(window.Shopify && window.Shopify.routes && window.Shopify.routes.root
? window.Shopify.routes.root
: '/') + 'cart/add.js',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify(payload),
}
)
.then(function (r) {
if (!r.ok) throw new Error('add failed');
return r.json();
})
.then(function (data) {
btn.innerText = 'Added ✓';
btn.disabled = true;
document.dispatchEvent(
new CustomEvent('cart:update', {
bubbles: true,
detail: {
resource: data,
sourceId: 'onhow-studio-upsell',
data: {
sections: data.sections || {},
},
},
})
);
var drawer = document.querySelector('cart-drawer-component');
if (drawer && typeof drawer.open === 'function') drawer.open();
})
.catch(function () {
btn.innerText = 'Error';
setTimeout(function () {
btn.innerText = originalText;
btn.disabled = false;
}, 2000);
});
});
})();
</script>
{% endif %}
{% comment %}
<!-- Designed by ONHOW Studio YouTube Channel - Anas El Medlaoui -->
{% endcomment %}

