← back to Designer Wallcoverings
DW PDP restyle: size-select -> pills + uniform CTA pill layout (theme-5.0-duplicate)
6b98ef31b1df651c5d4ab48a974d693bc6d06736 · 2026-06-22 17:09:36 -0700 · Steve
Progressive enhancement: native single-option-selector kept (visually hidden)
so variant/cart/cowlendar/MOQ JS unchanged; pills set value + dispatch native
change. CTAs relaid into Request Sample + Spec Sheet row / Add to Cart below.
Global include in layout/theme.liquid next to dw-card-hover.js.
Files touched
A shopify/theme-5.0-duplicate/assets/dw-pdp-restyle.cssA shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.jsM shopify/theme-5.0-duplicate/layout/theme.liquid
Diff
commit 6b98ef31b1df651c5d4ab48a974d693bc6d06736
Author: Steve <steve@designerwallcoverings.com>
Date: Mon Jun 22 17:09:36 2026 -0700
DW PDP restyle: size-select -> pills + uniform CTA pill layout (theme-5.0-duplicate)
Progressive enhancement: native single-option-selector kept (visually hidden)
so variant/cart/cowlendar/MOQ JS unchanged; pills set value + dispatch native
change. CTAs relaid into Request Sample + Spec Sheet row / Add to Cart below.
Global include in layout/theme.liquid next to dw-card-hover.js.
---
.../theme-5.0-duplicate/assets/dw-pdp-restyle.css | 160 +++++++++++++++++++++
.../assets/dw-pdp-size-pills.js | 110 ++++++++++++++
shopify/theme-5.0-duplicate/layout/theme.liquid | 3 +
3 files changed, 273 insertions(+)
diff --git a/shopify/theme-5.0-duplicate/assets/dw-pdp-restyle.css b/shopify/theme-5.0-duplicate/assets/dw-pdp-restyle.css
new file mode 100644
index 00000000..dd09d136
--- /dev/null
+++ b/shopify/theme-5.0-duplicate/assets/dw-pdp-restyle.css
@@ -0,0 +1,160 @@
+/* ==========================================================================
+ dw-pdp-restyle.css (Designer Wallcoverings PDP restyle, 2026-06-22)
+ Reference-design pass on the product page:
+ - SIZE selector -> two pill buttons (progressive enhancement; the native
+ <select.single-option-selector> stays in the DOM, visually hidden, so
+ all variant / cart / cowlendar / MOQ JS keeps reading it).
+ - REQUEST SAMPLE / SPEC SHEET / ADD TO CART -> three uniform rounded
+ pills, laid out: [Request Sample] [Spec Sheet] on one row, Add to Cart
+ below. Existing hrefs/handlers/classes untouched; restyle/relayout only.
+ Scoped to .template-product so nothing leaks to other templates.
+ ========================================================================== */
+
+/* --- Token: keep pill radius/font consistent across size pills + CTAs ------ */
+:root {
+ --dw-pill-radius: 99px;
+ --dw-pill-font: Lora, serif;
+}
+
+/* ==========================================================================
+ 1. SIZE PILLS
+ ========================================================================== */
+
+/* Hide the native size <select> but KEEP it operable for JS (.value/.dispatch).
+ We only hide it once our pills have been built (data-dw-pilled="1"), so on a
+ no-JS render the original dropdown is still usable. */
+.template-product select.single-option-selector[data-dw-pilled="1"] {
+ position: absolute !important;
+ width: 1px !important;
+ height: 1px !important;
+ padding: 0 !important;
+ margin: -1px !important;
+ overflow: hidden !important;
+ clip: rect(0 0 0 0) !important;
+ white-space: nowrap !important;
+ border: 0 !important;
+}
+
+.template-product .dw-size-pills {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10px;
+ margin: 6px 0 18px;
+}
+
+.template-product .dw-size-pill {
+ font-family: var(--dw-pill-font);
+ font-weight: 700;
+ font-size: 12px;
+ letter-spacing: 0.02em;
+ text-transform: uppercase;
+ line-height: 1.1;
+ cursor: pointer;
+ padding: 14px 22px;
+ min-height: 46px;
+ border-radius: var(--dw-pill-radius);
+ border: 1.5px solid #111;
+ background: #fff;
+ color: #111;
+ transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
+ -webkit-appearance: none;
+ appearance: none;
+}
+
+.template-product .dw-size-pill:hover {
+ background: #f2f2f2;
+}
+
+.template-product .dw-size-pill.is-active {
+ background: #111;
+ color: #fff;
+ border-color: #111;
+}
+
+.template-product .dw-size-pill.is-active:hover {
+ background: #000;
+}
+
+.template-product .dw-size-pill.is-unavailable,
+.template-product .dw-size-pill:disabled {
+ opacity: 0.45;
+ cursor: not-allowed;
+ text-decoration: line-through;
+}
+
+/* When the size pills are present we don't need the legacy plain-text
+ ".last_variant" echo of the option value cluttering the column. The
+ theme JS still toggles it for the display_variant=="no" single-variant
+ case; we only hide it once pills exist as a sibling. */
+.template-product .dw-size-pills ~ .selector-wrapper .last_variant {
+ /* leave theme behavior intact; no override needed */
+}
+
+/* ==========================================================================
+ 2. CTA PILL ROW (Request Sample + Spec Sheet on a row, Add to Cart below)
+ The existing buttons already share border-radius:99px + black fill from
+ custom.css. Here we only normalize sizing and arrange them in the
+ reference 2-up + full-width layout.
+ ========================================================================== */
+
+.template-product .product-add-to-cart {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 12px;
+ align-items: stretch;
+ max-width: 432px; /* ~ two 206px pills + gap */
+}
+
+/* Every primary CTA pill: uniform height / font / weight / radius / color */
+.template-product .product-add-to-cart .dl-sample-btn,
+.template-product .product-add-to-cart .dl-second-sample-btn,
+.template-product .product-add-to-cart .add-to-cart,
+.template-product .product-add-to-cart .shopify-payment-button__button {
+ flex: 1 1 calc(50% - 6px);
+ width: auto !important; /* override fixed 206px so they share the row */
+ min-width: 0;
+ min-height: 48px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ margin: 0 !important;
+ border-radius: var(--dw-pill-radius) !important;
+ font-family: var(--dw-pill-font);
+ font-weight: 700;
+ font-size: 12px !important;
+ letter-spacing: 0.02em;
+ text-transform: uppercase;
+ box-sizing: border-box;
+}
+
+/* Add to Cart spans the full width on its own row, beneath the 2-up pills. */
+.template-product .product-add-to-cart .add-to-cart {
+ flex: 1 1 100%;
+}
+
+/* Spec-sheet button has its own inline-block style block in its snippet; make
+ sure it participates in the flex row like the other pills. */
+.template-product .product-add-to-cart .spec-sheet-btn {
+ display: inline-flex !important;
+ vertical-align: top;
+}
+
+/* Keep the hidden/unavailable helpers behaving (they were display utilities). */
+.template-product .product-add-to-cart .hidden {
+ display: none !important;
+}
+
+/* Mobile: stack everything full-width but keep the pill look. */
+@media screen and (max-width: 1024px) {
+ .template-product .product-add-to-cart {
+ max-width: none;
+ }
+ .template-product .product-add-to-cart .dl-sample-btn,
+ .template-product .product-add-to-cart .dl-second-sample-btn,
+ .template-product .product-add-to-cart .add-to-cart,
+ .template-product .product-add-to-cart .shopify-payment-button__button {
+ flex: 1 1 100%;
+ width: 100% !important;
+ max-width: none !important;
+ }
+}
diff --git a/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js b/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js
new file mode 100644
index 00000000..0a6db012
--- /dev/null
+++ b/shopify/theme-5.0-duplicate/assets/dw-pdp-size-pills.js
@@ -0,0 +1,110 @@
+/*
+ * dw-pdp-size-pills.js (Designer Wallcoverings PDP restyle, 2026-06-22)
+ *
+ * Progressive enhancement ONLY. We do NOT remove or replace the native
+ * <select class="single-option-selector"> that the theme's variant /
+ * cart / cowlendar / MOQ JS reads. We:
+ * 1. keep the <select> in the DOM (visually hidden via dw-pdp-restyle.css),
+ * 2. render one clickable pill <button> per <option>,
+ * 3. on click -> set select.value + dispatch a native 'change' event so
+ * the existing jQuery `.on('change', '.single-option-selector', ...)'
+ * handler in custom.js.liquid (and everything downstream) fires exactly
+ * as if the user had used the dropdown.
+ *
+ * Safe to load globally; it no-ops on any page without a size selector.
+ */
+(function () {
+ 'use strict';
+ if (window.__dwPdpSizePillsLoaded) return;
+ window.__dwPdpSizePillsLoaded = true;
+
+ var SELECTOR = 'select.single-option-selector';
+
+ function buildPills(select) {
+ if (!select || select.dataset.dwPilled === '1') return;
+ // Only enhance real size/option selectors with 2+ choices.
+ var opts = Array.prototype.slice.call(select.options);
+ if (opts.length < 1) return;
+
+ select.dataset.dwPilled = '1';
+
+ var wrap = document.createElement('div');
+ wrap.className = 'dw-size-pills';
+ wrap.setAttribute('role', 'radiogroup');
+ var lbl = select.getAttribute('data-option-name') ||
+ (select.options[0] && select.options[0].closest ? '' : '');
+ wrap.setAttribute('aria-label', lbl || 'Size');
+
+ opts.forEach(function (opt) {
+ var btn = document.createElement('button');
+ btn.type = 'button';
+ btn.className = 'dw-size-pill';
+ btn.setAttribute('role', 'radio');
+ btn.textContent = (opt.textContent || opt.value || '').trim();
+ btn.dataset.value = opt.value;
+ if (opt.disabled) {
+ btn.disabled = true;
+ btn.classList.add('is-unavailable');
+ }
+ if (opt.selected) {
+ btn.classList.add('is-active');
+ btn.setAttribute('aria-checked', 'true');
+ } else {
+ btn.setAttribute('aria-checked', 'false');
+ }
+ btn.addEventListener('click', function () {
+ if (btn.disabled) return;
+ if (select.value === opt.value && opt.selected) {
+ // already selected — still re-sync visual state
+ syncActive(wrap, select);
+ return;
+ }
+ select.value = opt.value;
+ // Native change so jQuery delegated handlers + theme JS all fire.
+ var evt;
+ try {
+ evt = new Event('change', { bubbles: true });
+ } catch (e) {
+ evt = document.createEvent('HTMLEvents');
+ evt.initEvent('change', true, false);
+ }
+ select.dispatchEvent(evt);
+ syncActive(wrap, select);
+ });
+ wrap.appendChild(btn);
+ });
+
+ // Insert the pills right before the (now hidden) select wrapper.
+ var anchor = select.closest('.selector-wrapper') || select.parentNode;
+ if (anchor && anchor.parentNode) {
+ anchor.parentNode.insertBefore(wrap, anchor);
+ }
+
+ // Keep pills in sync if the select changes from any other source.
+ select.addEventListener('change', function () {
+ syncActive(wrap, select);
+ });
+ }
+
+ function syncActive(wrap, select) {
+ var val = select.value;
+ Array.prototype.forEach.call(wrap.querySelectorAll('.dw-size-pill'), function (b) {
+ var on = b.dataset.value === val;
+ b.classList.toggle('is-active', on);
+ b.setAttribute('aria-checked', on ? 'true' : 'false');
+ });
+ }
+
+ function init() {
+ var selects = document.querySelectorAll(SELECTOR);
+ Array.prototype.forEach.call(selects, buildPills);
+ }
+
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', init);
+ } else {
+ init();
+ }
+ // Re-run shortly after load in case theme JS injects/reorders selectors.
+ window.addEventListener('load', function () { setTimeout(init, 600); });
+})();
diff --git a/shopify/theme-5.0-duplicate/layout/theme.liquid b/shopify/theme-5.0-duplicate/layout/theme.liquid
index 6727e422..7a0347ad 100644
--- a/shopify/theme-5.0-duplicate/layout/theme.liquid
+++ b/shopify/theme-5.0-duplicate/layout/theme.liquid
@@ -1020,5 +1020,8 @@ alt="web statistics"></a></div></noscript>
<script src="{{ 'dw-pj-hide.js' | asset_url }}" defer></script>
{%- comment -%} DW card hover label: Pattern, Color + Vendor on hover (2026-06-22) {%- endcomment -%}
<script src="{{ 'dw-card-hover.js' | asset_url }}" defer></script>
+{%- comment -%} DW PDP restyle: size <select> -> pills + uniform CTA pill layout (2026-06-22) {%- endcomment -%}
+{{ 'dw-pdp-restyle.css' | asset_url | stylesheet_tag }}
+<script src="{{ 'dw-pdp-size-pills.js' | asset_url }}" defer></script>
</body>
</html>
← 19ae0d34 auto-save: 2026-06-22T17:07:33 (6 files) — shopify/scripts/b
·
back to Designer Wallcoverings
·
5.1 dev: horizontal collapsible Boost filter bar (dw-filter- 8e45fc21 →