Shopify Template
This is the Shopify template we used to mock up the rendered HTML.
It mirrors the live Shopify behavior (variants, price, stock, and Add to Cart) so what you see here matches how the real product page works.
-------------- classic-ceramic-mug.template --------------
{% comment %}
templates/product.classic-ceramic-mug.liquid
- Two options expected: Color (White/Black) and Pack (Single/Two-Pack)
- Uses native product form fields but the CTA is a JS alert (no submit), per Response #9
- ?variant=<id>gt; preselect works
{% endcomment %}
{% layout none %}
<section class="pdp wrap" itemscope itemtype="https://schema.org/Product">gt;
<style>gt;
:root{--border:#e8eef5;--ink:#111;--muted:#555;--brand:#0d7da6}
*{box-sizing:border-box}
.wrap{max-width:1120px;margin:0 auto;padding:20px}
.muted{color:var(--muted)}
.grid{display:grid;grid-template-columns:1.1fr .9fr;gap:28px}
@media (max-width:980px){.grid{grid-template-columns:1fr}}
.panel{background:#fff;border:1px solid var(--border);border-radius:14px;padding:14px}
.gallery img{width:100%;height:auto;border-radius:12px;display:block}
h1{margin:.2em 0 .4em}
.price{font-weight:700;font-size:1.25rem;margin:.4em 0}
.row{display:flex;align-items:center;gap:10px;margin:8px 0}
.row label{min-width:72px;font-weight:600}
.row select,.row input[type=number]{padding:10px 12px;border:1px solid var(--border);border-radius:10px}
.cta-row{display:flex;gap:12px;flex-wrap:wrap;margin:12px 0 4px}
.btn{padding:12px 16px;border-radius:12px;border:1px solid var(--brand);background:var(--brand);color:#fff;font-weight:800;cursor:pointer;text-decoration:none}
.btn[disabled]{opacity:.5;cursor:not-allowed}
details{border:1px solid var(--border);border-radius:12px;padding:10px 12px;margin:10px 0;background:#fff}
details summary{cursor:pointer;font-weight:600}
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;margin:14px 0}
.facts li{border:1px solid var(--border);border-radius:12px;padding:10px;list-style:none;background:#f7f9fb}
.proof{scroll-margin-top:80px}
.notice{background:#fff8e1;border:1px solid #ffe8a3;color:#5a4b00;padding:8px 12px;border-radius:10px;margin:8px 0 12px}
</style>gt;
{% assign product_obj = product %}
{% assign sel = product_obj.selected_or_first_available_variant %}
<!-- Header (breadcrumb removed per Response #9) -->gt;
<header>gt;
<h1 itemprop="name">gt;{{ product_obj.title }}</h1>gt;
{% if product_obj.description != blank %}
<p class="muted" itemprop="description">gt;
{{ product_obj.description | strip_html | truncate: 260 }}
</p>gt;
{% endif %}
</header>gt;
<div class="grid">gt;
<!-- Left: gallery + proof -->gt;
<section class="panel">gt;
<div class="gallery">gt;
{% assign first_image = product_obj.featured_image | default: product_obj.images.first %}
{% if first_image %}
<img src="{{ first_image | image_url: width: 1400 }}"
alt="{{ product_obj.title | escape }}"
loading="eager" decoding="async">gt;
{% endif %}
</div>gt;
<details open class="proof" id="proof-summary">gt;
<summary>gt;Description</summary>gt;
<p>gt;{{ product_obj.metafields.custom.short_description | default: "A clean, modern mug you'll reach for every morning. Smooth lip, comfortable handle, and a lead-free glaze that holds up to daily use. Dishwasher & microwave safe." }}</p>gt;
</details>gt;
<details class="proof" id="proof-variants">gt;
<summary>gt;Colors & packs (proof)</summary>gt;
<p>gt;Available in <strong>gt;White</strong>gt; or <strong>gt;Black</strong>gt;, as a <strong>gt;Single</strong>gt; or <strong>gt;Two-Pack</strong>gt;. Choose your combo on the right.</p>gt;
</details>gt;
</section>gt;
<!-- Right: buy box -->gt;
<aside class="panel" role="complementary">gt;
<!-- Live price & status -->gt;
<p class="price" id="pdp-price" aria-live="polite">gt;
{{ sel.price | money_with_currency }}
{% if sel.compare_at_price >gt; sel.price %}
<span class="muted" style="text-decoration:line-through;margin-left:6px">gt;
{{ sel.compare_at_price | money_with_currency }}
</span>gt;
{% endif %}
</p>gt;
{% unless sel.available %}
<div class="notice" id="pdp-status">gt;Selected option: <strong>gt;Sold out</strong>gt;</div>gt;
{% endunless %}
{% form 'product', product_obj, id: 'pdp-form', novalidate: 'novalidate' %}
<!-- Option selects (Color / Pack) -->gt;
{% for option in product_obj.options_with_values %}
<div class="row">gt;
<label for="opt-{{ forloop.index0 }}">gt;{{ option.name }}</label>gt;
<select id="opt-{{ forloop.index0 }}"
name="options[{{ option.name }}]"
data-option-index="{{ forloop.index0 }}">gt;
{% for val in option.values %}
<option value="{{ val | escape }}"
{% if option.selected_value == val %}selected{% endif %}>gt;
{{ val }}
</option>gt;
{% endfor %}
</select>gt;
</div>gt;
{% endfor %}
<!-- Quantity -->gt;
<div class="row">gt;
<label for="qty">gt;Qty</label>gt;
<input id="qty" type="number" name="quantity" min="1" value="1" inputmode="numeric">gt;
</div>gt;
<!-- Hidden input receives the selected variant.id -->gt;
<input type="hidden" name="id" value="{{ sel.id }}" id="variant-id">gt;
<!-- CTA changed to alert summary per Response #9 -->gt;
<div class="cta-row">gt;
<button class="btn" id="btn-atc" type="button"
{% unless sel.available %}disabled{% endunless %}>gt;
{% if sel.available %}Add to cart{% else %}Sold out{% endif %}
</button>gt;
</div>gt;
{% endform %}
<!-- Key facts -->gt;
<ul class="facts" aria-label="Key details">gt;
<li>gt;12 oz / 355 ml</li>gt;
<li>gt;Lead-free glaze</li>gt;
<li>gt;Dishwasher & microwave safe</li>gt;
<li>gt;White or Black</li>gt;
<li>gt;Single or Two-Pack</li>gt;
</ul>gt;
</aside>gt;
</div>gt;
-------------- classic-ceramic-mug.json --------------
{
"sections": {
"main": {
"type": "mug-classic",
"settings": {}
}
},
"order": [
"main"
]
}