I’m working on a client project and need help setting up a custom size option directly on the product page — without using any third-party app.
Here’s what we want:
A dropdown for size options (S, M, L, etc.), with “Custom” as one of the choices.
When a customer selects “Custom” from the dropdown, a form should pop up or appear on the page.
The form would allow them to fill in basic measurements (e.g., shoulder, bust, waist, hip, height).
These measurements should be submitted along with the product (likely as line item properties).
Is there a recommended way to implement this using custom Liquid in a Shopify theme? Has anyone done this before or can share a starting point?
I’ve actually done this for a few clients before, so I’d be happy to share my approach!
This is totally doable with some custom Liquid code and JavaScript. I’ve attached a code snippet below that should give you a solid starting point.
Basically, what this does is:
Adds “Custom” as an option in your size dropdown
Shows a measurement form when “Custom” is selected
Captures those measurements as line item properties that show up in the order
{% comment %}
Add this code to your product-template.liquid file where your variant selection appears
{% endcomment %}
<div class="product-form">
{% form 'product', product %}
<select name="id" id="ProductSelect" class="product-form__variants">
{% for variant in product.variants %}
{% if variant.available %}
<option value="{{ variant.id }}">
{{ variant.title }} - {{ variant.price | money }}
</option>
{% else %}
<option disabled="disabled">
{{ variant.title }} - Sold Out
</option>
{% endif %}
{% endfor %}
</select>
{% comment %}
Size selector - Assumes you have a variant option called "Size"
Make sure to adjust based on how your variants are set up
{% endcomment %}
{% if product.options_by_name['Size'] %}
<div class="size-selector">
<label for="Size">Size</label>
<select name="options[Size]" id="SizeSelector">
{% for value in product.options_by_name['Size'].values %}
<option value="{{ value }}">{{ value }}</option>
{% endfor %}
<option value="Custom">Custom</option>
</select>
</div>
{% endif %}
{% comment %} Custom size form that will appear when "Custom" is selected {% endcomment %}
<div id="custom-size-form" style="display: none;">
<h3>Enter Your Custom Measurements</h3>
<div class="measurement-fields">
<div class="measurement-field">
<label for="measurement-shoulder">Shoulder (inches)</label>
<input type="number" id="measurement-shoulder" name="properties[Shoulder]" step="0.1">
</div>
<div class="measurement-field">
<label for="measurement-bust">Bust (inches)</label>
<input type="number" id="measurement-bust" name="properties[Bust]" step="0.1">
</div>
<div class="measurement-field">
<label for="measurement-waist">Waist (inches)</label>
<input type="number" id="measurement-waist" name="properties[Waist]" step="0.1">
</div>
<div class="measurement-field">
<label for="measurement-hip">Hip (inches)</label>
<input type="number" id="measurement-hip" name="properties[Hip]" step="0.1">
</div>
<div class="measurement-field">
<label for="measurement-height">Height (inches)</label>
<input type="number" id="measurement-height" name="properties[Height]" step="0.1">
</div>
</div>
</div>
<button type="submit" name="add" id="AddToCart" class="btn">
<span id="AddToCartText">Add to Cart</span>
</button>
{% endform %}
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var sizeSelector = document.getElementById('SizeSelector');
var customSizeForm = document.getElementById('custom-size-form');
// Function to toggle custom size form visibility
function toggleCustomSizeForm() {
if (sizeSelector.value === 'Custom') {
customSizeForm.style.display = 'block';
} else {
customSizeForm.style.display = 'none';
}
}
// Add event listener to size selector
if (sizeSelector) {
sizeSelector.addEventListener('change', toggleCustomSizeForm);
// Check initial state
toggleCustomSizeForm();
}
// Validate before form submission
document.querySelector('form[action="/cart/add"]').addEventListener('submit', function(e) {
if (sizeSelector && sizeSelector.value === 'Custom') {
// Simple validation for custom measurements
var allFieldsFilled = true;
var measurementFields = document.querySelectorAll('#custom-size-form input[type="number"]');
measurementFields.forEach(function(field) {
if (!field.value || field.value.trim() === '') {
allFieldsFilled = false;
}
});
if (!allFieldsFilled) {
e.preventDefault();
alert('Please fill in all measurement fields for custom sizing.');
}
}
});
});
</script>
<style>
#custom-size-form {
margin: 20px 0;
padding: 15px;
border: 1px solid #e8e8e8;
border-radius: 4px;
background: #f9f9f9;
}
.measurement-fields {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin-top: 15px;
}
.measurement-field {
display: flex;
flex-direction: column;
}
.measurement-field label {
margin-bottom: 5px;
font-size: 14px;
}
.measurement-field input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
You’ll need to tweak this a bit depending on your theme structure, but the general approach should work well. It’s easy to customize - just add/remove measurement fields as needed and adjust the styling to match your store’s design.
For one client, I also added a “measurement guide” with illustrations showing customers exactly where to measure, which helped reduce errors. Just a thought if that might be useful for your project too.
Let me know if you have any questions or run into any issues implementing this! Happy to help troubleshoot if needed.
Hi All - thanks for the help! I tried these solutions - but somehow still did not work - i added the sizes as variants - some said to add them as category metafields.. not sure what to do? can i share the unpublished website url here for help?
Hi All - thanks for the help! I tried these solutions - but somehow still did not work - i added the sizes as variants - some said to add them as category metafields.. not sure what to do? can i share the unpublished website url here for help?
Of course it would not – I had no idea how your option is actually called and the code was for my test store, where it worked flawlessly.
For you store the CSS part of the code should be
See the selector variant-selects:has([value=“Custom”][selected]) + .lips ?
This means the rule will apply to the .lips element which is placed directly after variant-selects where option with value=“Custom” is selected – basically rule means that if “Custom” is selected in drop-down, show the extra input fields.
For my demo it had [value=“Original”] – meaning extra fields were shown only for Original variant of the product, that’s why it did not work for your store.