Shopify Line Item Properties Generator
Add text, dropdown, date and file-upload fields to a product form, with fields that only show when relevant.
Your details
Your snippet file (snippets/custom-options.liquid)
{%- comment -%}
Custom order options. Uses {% form 'product', product %}, which sets enctype="multipart/form-data"
automatically, so the file field works without extra setup.
{%- endcomment -%}
{%- style -%}
.ea-lifields{display:flex;flex-direction:column;gap:.75rem;margin:1rem 0}
.ea-lifield__label{display:flex;flex-direction:column;gap:.3rem;font-size:13px;font-weight:600}
.ea-lifield input,.ea-lifield select,.ea-lifield textarea{font:inherit;font-weight:400;padding:.5em .6em;border:1px solid #ccc;border-radius:6px}
.ea-lifield[hidden]{display:none}
{%- endstyle -%}
{%- form 'product', product -%}
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
<div class="ea-lifields">
<div class="ea-lifield">
<label class="ea-lifield__label">Custom text (max 50 chars)
<input type="text" name="properties[Custom text (max 50 chars)]" maxlength="200">
</label>
</div>
<div class="ea-lifield">
<label class="ea-lifield__label">Gift wrap
<select name="properties[Gift wrap]"><option value="No">No</option><option value="Yes">Yes</option></select>
</label>
</div>
<div class="ea-lifield" data-show-if-name="properties[Gift wrap]" data-show-if-value="Yes" hidden>
<label class="ea-lifield__label">Gift message
<input type="text" name="properties[Gift message]" maxlength="200">
</label>
</div>
<div class="ea-lifield">
<label class="ea-lifield__label">Requested delivery date *
<input type="date" name="properties[Requested delivery date]" required>
</label>
</div>
<div class="ea-lifield">
<label class="ea-lifield__label">Upload your design
<input type="file" name="properties[Upload your design]">
</label>
</div>
</div>
<button type="submit">Add to cart</button>
{%- endform -%}
<script>
document.querySelectorAll('.ea-lifields').forEach(function (wrap) {
function sync() {
wrap.querySelectorAll('[data-show-if-name]').forEach(function (row) {
var ctrl = wrap.querySelector('[name="' + row.dataset.showIfName + '"]');
var match = ctrl && ctrl.value === row.dataset.showIfValue;
row.hidden = !match;
row.querySelectorAll('input,select,textarea').forEach(function (el) { el.disabled = !match; });
});
}
wrap.addEventListener('change', sync);
sync();
});
</script>To install: in Shopify admin go to Online Store → Themes, click … next to your theme → Edit code. Under Snippets choose Add a new snippet, name it as shown above, paste this code and save. This renders its own Add to cart button and form. If you already have one on the page, remove this one's button and move the .ea-lifields block inside your existing {% form 'product', product %} instead.
File uploads are hosted by Shopify automatically. Find them on the order's line item properties in your Shopify admin, they show as a link.
The required attribute only stops empty submissions from this form. It doesn't stop an empty property arriving through another channel, like the API.
Live preview
Replacing Shopify's retired UI elements generator
Shopify's old "Build a custom product options form" tool (the UI elements generator) is retired. Custom fields on a product form still work the same way they always have: any input named properties[Your Label] inside the add-to-cart form is saved on the order as a line item property, and shows on the cart, checkout and order pages next to that item.
Describe your fields one per line (type, label, options, required), and this builds the matching inputs plus a small standalone form using Shopify's own {% form 'product', product %} tag, so the submission behaves exactly like a normal add-to-cart.
- Prefix a field's label with an underscore in the code (or use the hidden field type) to store it without showing it to the customer at checkout, useful for internal notes like a batch code
- A file field adds
enctype="multipart/form-data"to the form automatically, required for uploads to work - Start a line with
?to make a field only appear when an earlier select field has a specific value
The required attribute this adds is a browser-side nicety only. It stops a shopper from submitting the form empty, but doesn't stop the property being empty if an order comes in another way (the API, a POS sale). Don't rely on it for anything that must never be blank.
Questions people ask
Where do custom fields show up after checkout?
On the cart page, checkout, the order confirmation, the customer's order history, and in your Shopify admin's order detail, unless you hid the property with an underscore prefix.
Can I limit how many characters a text field accepts?
Yes, set a max length in the field's options; it's enforced with the input's maxlength attribute.
Does a file upload cost anything or need an app?
No, Shopify hosts uploaded files itself when a form has enctype="multipart/form-data" and a type="file" input named properties[...]; no app is required.
Can properties change the price?
Not directly. Line item properties are notes on the order, they don't add a charge on their own. For paid options (like gift wrap for a fee), use a separate priced product or a Shopify Scripts/Functions-based approach instead.
Related tools
Last reviewed 30 September 2026.
