In this tutorial, we add section block for a tiered quantity selector with discounts displayed. This upgrade can boost your AOV and conversion rate by making the discounts front and center while also simplifying their buying process.
Compatible Themes: This code should work on all free Shopify themes (Dawn, Refresh, Craft, Studio, Publisher, Crave, Origin, Taste, Colorblock, Sense, Ride, Spotlight).
Update main-product.liquid
{%- when 'tiered_quantity_selector' -%}
{% render 'tiered-quantity-selector-custom', block: block, section: section %}
{
"type": "tiered_quantity_selector",
"name": "Tiered Quantity Selector",
"limit": 1,
"settings": [
{
"type": "header",
"content": "Option 1 Settings"
},
{
"type": "text",
"id": "option_1_label",
"label": "Option 1 Label",
"default": "1 Pack"
},
{
"type": "number",
"id": "option_1_quantity",
"label": "Option 1 Quantity",
"default": 1
},
{
"type": "range",
"id": "option_1_discount_percentage",
"label": "Option 1 Discount Percentage",
"default": 0,
"min": 0,
"max": 100
},
{
"type": "checkbox",
"id": "option_1_badge_enable",
"label": "Enable Badge for Option 1",
"default": false
},
{
"type": "text",
"id": "option_1_badge_text",
"label": "Option 1 Badge Text",
"default": "Most Popular"
},
{
"type": "header",
"content": "Option 2 Settings"
},
{
"type": "text",
"id": "option_2_label",
"label": "Option 2 Label",
"default": "3 Pack"
},
{
"type": "number",
"id": "option_2_quantity",
"label": "Option 2 Quantity",
"default": 3
},
{
"type": "range",
"id": "option_2_discount_percentage",
"label": "Option 2 Discount Percentage",
"default": 10,
"min": 0,
"max": 100
},
{
"type": "checkbox",
"id": "option_2_badge_enable",
"label": "Enable Badge for Option 2",
"default": true
},
{
"type": "text",
"id": "option_2_badge_text",
"label": "Option 2 Badge Text",
"default": "Most Popular"
},
{
"type": "header",
"content": "Option 3 Settings"
},
{
"type": "text",
"id": "option_3_label",
"label": "Option 3 Label",
"default": "5 Pack"
},
{
"type": "number",
"id": "option_3_quantity",
"label": "Option 3 Quantity",
"default": 5
},
{
"type": "range",
"id": "option_3_discount_percentage",
"label": "Option 3 Discount Percentage",
"default": 20,
"min": 0,
"max": 100
},
{
"type": "checkbox",
"id": "option_3_badge_enable",
"label": "Enable Badge for Option 3",
"default": false
},
{
"type": "text",
"id": "option_3_badge_text",
"label": "Option 3 Badge Text",
"default": "Most Popular"
},
{
"type": "header",
"content": "General Settings"
},
{
"type": "checkbox",
"id": "show_quantity_label",
"label": "Show Quantity Selector Label",
"default": true
},
{
"type": "text",
"id": "quantity_label_text",
"label": "Quantity Selector Label Text",
"default": "Select Quantity"
},
{
"type": "text",
"id": "per_unit_label",
"label": "Per Unit Label",
"default": "unit"
},
{
"type": "checkbox",
"id": "show_strikethrough",
"label": "Show Strikethrough Pricing",
"default": true
},
{
"type": "checkbox",
"id": "show_total_pricing",
"label": "Show Total Pricing",
"default": true
},
{
"type": "checkbox",
"id": "show_per_unit",
"label": "Show Per Unit Pricing",
"default": true
},
{
"type": "checkbox",
"id": "show_savings_labels",
"label": "Show Savings Labels (All)",
"default": true
},
{
"type": "checkbox",
"id": "show_zero_percent_savings",
"label": "Show 0% Savings Label",
"default": true
},
{
"type": "header",
"content": "Formatting Settings"
},
{
"type": "range",
"id": "border_radius",
"label": "Border Radius",
"default": 0.5,
"min": 0,
"max": 2,
"step": 0.1,
"unit": "rem"
},
{
"type": "range",
"id": "option_bottom_spacing",
"label": "Option Bottom Spacing",
"default": 2.5,
"min": 1,
"max": 5,
"step": 0.1,
"unit": "rem"
},
{
"type": "range",
"id": "label_font_size",
"label": "Label Font Size",
"default": 1.7,
"min": 1,
"max": 3,
"step": 0.1,
"unit": "rem"
},
{
"type": "range",
"id": "compare_price_font_size",
"label": "Compare Price Font Size",
"default": 1.3,
"min": 0.5,
"max": 2,
"step": 0.1,
"unit": "rem"
},
{
"type": "range",
"id": "final_price_font_size",
"label": "Final Price Font Size",
"default": 1.5,
"min": 0.5,
"max": 2,
"step": 0.1,
"unit": "rem"
},
{
"type": "range",
"id": "per_unit_font_size",
"label": "Per Unit Price Font Size",
"default": 1.0,
"min": 0.5,
"max": 2,
"step": 0.1,
"unit": "rem"
},
{
"type": "color",
"id": "text_color_unselected",
"label": "Button Text Color (Unselected)",
"default": "#121212"
},
{
"type": "color",
"id": "text_color_selected",
"label": "Selected Button Text Color",
"default": "#FFFFFF"
},
{
"type": "color",
"id": "selected_button_bg_color",
"label": "Selected Button Background Color",
"default": "#121212"
},
{
"type": "color",
"id": "savings_text_color",
"label": "Savings Label Text Color",
"default": "#ffffff"
},
{
"type": "range",
"id": "savings_label_font_size",
"label": "Savings Label Font Size",
"default": 1.1,
"min": 0.5,
"max": 1.5,
"step": 0.1,
"unit": "rem"
},
{
"type": "color",
"id": "savings_bg_color",
"label": "Savings Label Background Color",
"default": "#334FB4"
},
{
"type": "color",
"id": "badge_bg_color",
"label": "Badge Background Color",
"default": "#e33e3e"
},
{
"type": "range",
"id": "badge_font_size",
"label": "Badge Font Size",
"default": 1.0,
"min": 0.5,
"max": 2,
"step": 0.1,
"unit": "rem"
},
{
"type": "color",
"id": "badge_font_color",
"label": "Badge Font Color",
"default": "#ffffff"
}
]
},
Create new liquid file tiered-quantity-selector-custom.liquid
{% assign product_form_id = 'product-form-' | append: section.id %}
{% assign base_price = product.selected_or_first_available_variant.price %}
<div class="tiered-quantity-selector" {{ block.shopify_attributes }}>
<style>
.tiered-quantity-options {
--selected-bg-color: {{ block.settings.selected_button_bg_color }};
--savings-text-color: {{ block.settings.savings_text_color }};
--savings-bg-color: {{ block.settings.savings_bg_color }};
--border-radius: {{ block.settings.border_radius }}rem;
--option-bottom-spacing: {{ block.settings.option_bottom_spacing }}rem;
--compare-price-font-size: {{ block.settings.compare_price_font_size }}rem;
--final-price-font-size: {{ block.settings.final_price_font_size }}rem;
--per-unit-font-size: {{ block.settings.per_unit_font_size }}rem;
--label-font-size: {{ block.settings.label_font_size }}rem;
--text-color-unselected: {{ block.settings.text_color_unselected }};
--text-color-selected: {{ block.settings.text_color_selected }};
--savings-label-font-size: {{ block.settings.savings_label_font_size }}rem;
--badge-bg-color: {{ block.settings.badge_bg_color }};
--badge-font-size: {{ block.settings.badge_font_size }}rem;
--badge-font-color: {{ block.settings.badge_font_color }};
}
.tiered-quantity-selector {
margin: 1em 0;
}
.tiered-quantity-options {
display: flex;
gap: 1em;
margin-top: 0.7rem;
flex-wrap: wrap;
align-items: stretch;
}
.tiered-option-wrapper {
position: relative;
display: flex;
flex: 1;
flex-direction: column;
align-items: center;
}
.tiered-option {
cursor: pointer;
border: 1px solid #ccc;
padding: 0.5em;
text-align: center;
transition: all 0.3s;
background: #fff;
font-size: var(--pricing-font-size);
color: var(--text-color-unselected);
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: var(--border-radius);
position: relative;
padding-bottom: var(--option-bottom-spacing);
overflow: hidden;
width: 100%;
}
.tiered-option--active {
background: var(--selected-bg-color);
color: var(--text-color-selected);
}
.tiered-option:hover {
border-color: #000;
}
.tiered-option__badge {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -80%);
display: inline-block;
background: var(--badge-bg-color);
color: var(--badge-font-color);
font-size: var(--badge-font-size);
font-weight: bold;
text-align: center;
white-space: nowrap;
padding: 0.1em 0.5em;
border-radius: var(--border-radius);
z-index: 2;
}
.tiered-option__label {
font-weight: 600;
margin-bottom: 0.5em;
font-size: var(--label-font-size);
}
.tiered-option__prices {
margin: 0.5em 0;
}
.tiered-option__compare-price {
color: inherit;
opacity: 0.75;
text-decoration: line-through;
display: block;
margin-bottom: 0.25em;
font-size: var(--compare-price-font-size);
}
.tiered-option__final-price {
font-weight: bold;
font-size: 1.1em;
margin-bottom: 0.25em;
font-size: var(--final-price-font-size);
}
.tiered-option__per-unit {
font-size: var(--per-unit-font-size);
color: inherit;
opacity: 0.75;
margin-bottom: 0.5em;
}
.tiered-option__discount-area {
position: absolute;
bottom: -0.25px;
left: -1px;
width: calc(100% + 2px);
box-sizing: border-box;
text-align: center;
padding: 0.5em;
background: var(--savings-bg-color);
color: var(--savings-text-color);
font-size: var(--savings-label-font-size);
font-weight: bold;
transform: translateZ(0);
will-change: transform;
}
</style>
<!-- Hidden quantity input -->
<input type="hidden" name="quantity" id="Quantity-{{ section.id }}" value="1" form="{{ product_form_id }}" />
{% assign per_unit_label = block.settings.per_unit_label %}
{% assign show_zero_percent_savings = block.settings.show_zero_percent_savings %}
{% assign show_savings_labels = block.settings.show_savings_labels %}
{% assign show_strikethrough = block.settings.show_strikethrough %}
{% assign show_per_unit = block.settings.show_per_unit %}
{% assign show_total_pricing = block.settings.show_total_pricing %}
{% assign show_quantity_label = block.settings.show_quantity_label %}
{% assign quantity_label_text = block.settings.quantity_label_text %}
{% if show_quantity_label %}
<legend class="form__label">{{ quantity_label_text }}</legend>
{% endif %}
<div class="tiered-quantity-options" data-quantity-input-id="Quantity-{{ section.id }}">
{% assign option_numbers = "1,2,3" | split: "," %}
{% for i in option_numbers %}
{% assign label_key = "option_" | append: i | append: "_label" %}
{% assign quantity_key = "option_" | append: i | append: "_quantity" %}
{% assign discount_pct_key = "option_" | append: i | append: "_discount_percentage" %}
{% assign badge_enable_key = "option_" | append: i | append: "_badge_enable" %}
{% assign badge_text_key = "option_" | append: i | append: "_badge_text" %}
{% assign label = block.settings[label_key] %}
{% assign quantity = block.settings[quantity_key] | plus: 0 %}
{% assign discount_pct = block.settings[discount_pct_key] | plus: 0 %}
{% assign badge_enable = block.settings[badge_enable_key] %}
{% assign badge_text = block.settings[badge_text_key] %}
{% if label != blank and quantity > 0 %}
{% assign compare_total_cents = quantity | times: base_price %}
{% assign discount_multiplier = 100 | minus: discount_pct %}
{% assign final_price_cents = compare_total_cents | times: discount_multiplier | divided_by: 100 %}
{% assign per_unit_cents = final_price_cents | divided_by: quantity %}
{% capture compare_price_formatted %}{{ compare_total_cents | money }}{% endcapture %}
{% capture final_price_formatted %}{{ final_price_cents | money }}{% endcapture %}
{% capture per_unit_price_formatted %}{{ per_unit_cents | money }}{% endcapture %}
{% assign show_compare = false %}
{% if discount_pct > 0 and show_strikethrough %}
{% assign show_compare = true %}
{% endif %}
{% assign show_discount = false %}
{% if show_savings_labels %}
{% if discount_pct > 0 %}
{% assign show_discount = true %}
{% elsif discount_pct == 0 and show_zero_percent_savings %}
{% assign show_discount = true %}
{% endif %}
{% endif %}
<div class="tiered-option-wrapper">
{% if badge_enable %}
<div class="tiered-option__badge">{{ badge_text }}</div>
{% endif %}
<button type="button"
class="tiered-option{% if forloop.first %} tiered-option--active{% endif %}"
data-quantity="{{ quantity }}">
<div class="tiered-option__content">
<div class="tiered-option__label">{{ label }}</div>
<div class="tiered-option__prices">
{% if show_compare %}
<span class="tiered-option__compare-price">{{ compare_price_formatted }}</span>
{% endif %}
{% if show_total_pricing %}
<span class="tiered-option__final-price">{{ final_price_formatted }}</span>
{% endif %}
{% if show_per_unit %}
<div class="tiered-option__per-unit">{{ per_unit_price_formatted }} / {{ per_unit_label }}</div>
{% endif %}
</div>
</div>
{% if show_discount %}
<div class="tiered-option__discount-area">
Save {{ discount_pct }}%
</div>
{% endif %}
</button>
</div>
{% endif %}
{% endfor %}
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var container = document.querySelector('.tiered-quantity-options[data-quantity-input-id="Quantity-{{ section.id }}"]');
if (!container) return;
var quantityInput = document.getElementById(container.dataset.quantityInputId);
var buttons = container.querySelectorAll('.tiered-option');
buttons.forEach(function(btn) {
btn.addEventListener('click', function() {
buttons.forEach(b => {
b.classList.remove('tiered-option--active');
b.style.background = '#fff';
b.style.color = 'var(--text-color-unselected)';
});
this.classList.add('tiered-option--active');
this.style.background = getComputedStyle(this).getPropertyValue('--selected-bg-color') || '#000';
this.style.color = 'var(--text-color-selected)';
var qty = parseInt(this.getAttribute('data-quantity'), 10);
if (quantityInput && !isNaN(qty)) {
quantityInput.value = qty;
quantityInput.dispatchEvent(new Event('change'));
}
});
});
});
</script>