{%- comment -%} MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections {%- endcomment -%} {%- comment -%} Featured product: one product you pick, with its image gallery, title, price, variant picker, quantity and add to cart, for a home page or landing page. The form posts to /cart/add, so it works without JavaScript (a plain variant menu); with JavaScript the options become buttons and the price, sale label, availability and image follow the chosen variant. Every word a shopper sees is a setting. Reads the product only; no ratings, stock counts or other made-up data. Depends on: snippets/lib-button.liquid {%- endcomment -%} {%- liquid assign s = section.settings assign p = s.product assign heading_tag = s.heading_tag | default: 'h2' assign uid = 'lib-fp-' | append: section.id assign eager = false if section.index <= 2 assign eager = true endif assign render_section = true if p == blank and request.design_mode == false assign render_section = false endif if p != blank assign current = p.selected_or_first_available_variant assign price = current.price | default: p.price assign compare = current.compare_at_price | default: 0 assign on_sale = false if compare > price assign on_sale = true endif assign has_options = true if p.has_only_default_variant or p.variants.size < 2 assign has_options = false endif assign first_media = p.media | where: 'media_type', 'image' | first assign option_names = p.options_with_values | map: 'name' | join: ' / ' endif assign media_sizes = '(min-width: 990px) 50vw, 100vw' if s.media_width == 'wide' assign media_sizes = '(min-width: 990px) 58vw, 100vw' endif -%} {%- if render_section -%} {%- endif -%} {% stylesheet %} .lib-featured-product { display: block; background-color: var(--lib-bg); color: var(--lib-text); padding: var(--lib-pt) 1rem var(--lib-pb); } .lib-featured-product__inner { display: grid; gap: clamp(1.75rem, 4vw, 4rem); max-width: 1200px; margin: 0 auto; } .lib-featured-product--full .lib-featured-product__inner { max-width: none; } .lib-featured-product__inner > * { min-width: 0; } @media (max-width: 749px) { .lib-featured-product { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); } .lib-featured-product[data-show='desktop'] { display: none; } } @media (min-width: 750px) { .lib-featured-product[data-show='mobile'] { display: none; } } @media (max-width: 989px) { .lib-featured-product[data-mobile-order='info_first'] .lib-featured-product__info { order: -1; } } @media (min-width: 990px) { .lib-featured-product__inner { grid-template-columns: 1fr 1fr; align-items: start; } .lib-featured-product[data-media-width='wide'] .lib-featured-product__inner { grid-template-columns: 7fr 5fr; } .lib-featured-product[data-media-position='right'] .lib-featured-product__media { order: 2; } .lib-featured-product[data-media-position='right'][data-media-width='wide'] .lib-featured-product__inner { grid-template-columns: 5fr 7fr; } .lib-featured-product__info { position: sticky; top: 2rem; } } /* Gallery: one image at a time, thumbnails underneath. */ .lib-featured-product__stage { position: relative; overflow: hidden; border-radius: var(--lib-radius); background: color-mix(in srgb, var(--lib-text) 6%, var(--lib-bg)); aspect-ratio: 1; } .lib-featured-product[data-ratio='portrait'] .lib-featured-product__stage { aspect-ratio: 4 / 5; } .lib-featured-product[data-ratio='landscape'] .lib-featured-product__stage { aspect-ratio: 4 / 3; } .lib-featured-product[data-ratio='adapt'] .lib-featured-product__stage { aspect-ratio: var(--lib-ratio, 1); } .lib-featured-product__slide { position: absolute; inset: 0; } .lib-featured-product__slide[hidden] { display: none; } .lib-featured-product__img { display: block; width: 100%; height: 100%; object-fit: cover; } .lib-featured-product__placeholder { fill: color-mix(in srgb, var(--lib-text) 25%, transparent); } .lib-featured-product__thumbs { display: flex; gap: 0.625rem; margin: 0.875rem 0 0; padding: 0.25rem; list-style: none; overflow-x: auto; scrollbar-width: thin; } .lib-featured-product__thumbs[hidden] { display: none; } .lib-featured-product__thumb { display: block; width: 4.5rem; height: 4.5rem; padding: 0; border: 1px solid var(--lib-border); border-radius: calc(var(--lib-radius) / 2); overflow: hidden; background: color-mix(in srgb, var(--lib-text) 6%, var(--lib-bg)); cursor: pointer; opacity: 0.7; transition: opacity 0.2s ease, border-color 0.2s ease; } .lib-featured-product__thumb:hover { opacity: 1; } .lib-featured-product__thumb[aria-current='true'] { opacity: 1; border-color: var(--lib-text); box-shadow: inset 0 0 0 1px var(--lib-text); } .lib-featured-product__thumb:focus-visible { outline: 2px solid var(--lib-text); outline-offset: 2px; } .lib-featured-product__thumb-img { display: block; width: 100%; height: 100%; object-fit: cover; } /* Info column and alignment: desktop, then mobile override. */ .lib-featured-product__info { display: flex; flex-direction: column; align-items: flex-start; text-align: left; } .lib-featured-product__info[data-align='center'] { align-items: center; text-align: center; } @media (max-width: 749px) { .lib-featured-product__info[data-align-m='left'] { align-items: flex-start; text-align: left; } .lib-featured-product__info[data-align-m='center'] { align-items: center; text-align: center; } } .lib-featured-product__info > * { margin: 0; } .lib-featured-product__vendor { margin-bottom: 0.75rem; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.75; } .lib-featured-product__title { font-size: clamp(1.75rem, 3vw, 2.5rem); line-height: 1.1; letter-spacing: -0.02em; text-wrap: balance; } .lib-featured-product__title--small { font-size: clamp(1.375rem, 2vw, 1.75rem); } .lib-featured-product__title--large { font-size: clamp(2rem, 4vw, 3.25rem); } .lib-featured-product__price { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.625rem; margin-top: 1rem; font-size: 1.25rem; } .lib-featured-product__info[data-align='center'] .lib-featured-product__price { justify-content: center; } @media (max-width: 749px) { .lib-featured-product__info[data-align-m='left'] .lib-featured-product__price { justify-content: flex-start; } .lib-featured-product__info[data-align-m='center'] .lib-featured-product__price { justify-content: center; } } .lib-featured-product__now { font-weight: 600; } .lib-featured-product__now.is-sale { color: var(--lib-accent); } .lib-featured-product__was { font-size: 1rem; opacity: 0.65; } .lib-featured-product__badge { align-self: center; padding: 0.3em 0.7em; border-radius: 999px; background: var(--lib-accent); color: var(--lib-accent-text); font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em; } .lib-featured-product__badge--muted { background: color-mix(in srgb, var(--lib-text) 12%, transparent); color: var(--lib-text); } .lib-featured-product__badge[hidden], .lib-featured-product__was[hidden] { display: none; } .lib-featured-product__form { display: flex; flex-direction: column; gap: 1.25rem; width: 100%; max-width: 30rem; margin-top: 1.75rem; text-align: left; } .lib-featured-product__label { display: block; margin: 0 0 0.5rem; padding: 0; font-size: 0.875rem; font-weight: 600; } .lib-featured-product__select { width: 100%; min-height: 2.75rem; padding: 0.5rem 0.75rem; border: 1px solid var(--lib-border); border-radius: calc(var(--lib-radius) / 2); background: transparent; color: inherit; font: inherit; } .lib-featured-product__option { min-width: 0; margin: 0; padding: 0; border: 0; } .lib-featured-product__option[hidden], .lib-featured-product__fallback[hidden] { display: none; } .lib-featured-product__values { display: flex; flex-wrap: wrap; gap: 0.5rem; } .lib-featured-product__choice { position: relative; display: inline-flex; } .lib-featured-product__radio { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; } .lib-featured-product__value { display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0.5rem 1.125rem; border: 1px solid var(--lib-border); border-radius: 999px; font-size: 0.9375rem; cursor: pointer; transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease; } .lib-featured-product__radio:hover + .lib-featured-product__value { border-color: var(--lib-text); } .lib-featured-product__radio:checked + .lib-featured-product__value { background: var(--lib-text); border-color: var(--lib-text); color: var(--lib-bg); } .lib-featured-product__radio:focus-visible + .lib-featured-product__value { outline: 2px solid var(--lib-text); outline-offset: 2px; } .lib-featured-product__choice[data-sold-out] .lib-featured-product__value { text-decoration: line-through; text-decoration-thickness: 1px; opacity: 0.6; } .lib-featured-product__choice[data-sold-out] .lib-featured-product__radio:checked + .lib-featured-product__value { opacity: 0.75; } .lib-featured-product__buy { display: flex; flex-wrap: wrap; gap: 0.75rem; } .lib-featured-product__qty { display: inline-flex; align-items: center; height: 3rem; border: 1px solid var(--lib-border); border-radius: 999px; } .lib-featured-product__step { display: grid; place-items: center; width: 2.75rem; height: 100%; padding: 0; border: 0; background: none; color: inherit; cursor: pointer; } .lib-featured-product__step[hidden] { display: none; } .lib-featured-product__step:focus-visible { outline: 2px solid var(--lib-text); outline-offset: -4px; border-radius: 999px; } .lib-featured-product__qty-input { width: 3.5rem; height: 100%; border: 0; background: none; color: inherit; font: inherit; text-align: center; appearance: textfield; -moz-appearance: textfield; } .lib-featured-product__qty-input::-webkit-inner-spin-button, .lib-featured-product__qty-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } .lib-featured-product__qty-input:focus-visible { outline: 2px solid var(--lib-text); outline-offset: -2px; border-radius: 4px; } .lib-featured-product__add { flex: 1 1 12rem; min-height: 3rem; padding: 0.85rem 1.5rem; border: 0; border-radius: 999px; background: var(--lib-accent); color: var(--lib-accent-text); font: inherit; font-weight: 600; cursor: pointer; transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease; } .lib-featured-product__add:hover:not(:disabled) { transform: translateY(-1px); box-shadow: 0 8px 20px -10px rgb(0 0 0 / 0.45); } .lib-featured-product__add:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 3px; } .lib-featured-product__add:disabled { cursor: not-allowed; opacity: 0.55; } .lib-featured-product__description { margin-top: 1.75rem; max-width: 34rem; font-size: 1rem; line-height: 1.65; opacity: 0.85; } .lib-featured-product__description > :first-child { margin-top: 0; } .lib-featured-product__description > :last-child { margin-bottom: 0; } .lib-featured-product__description a { color: inherit; } .lib-featured-product__details { margin-top: 1.5rem; } .lib-featured-product__sr { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; } .lib-featured-product__sr[hidden] { display: none; } /* Motion: gallery and info fade up as they scroll into view (scroll-driven animations only). */ @supports (animation-timeline: view()) { @media (prefers-reduced-motion: no-preference) { .lib-featured-product[data-animate] .lib-featured-product__media, .lib-featured-product[data-animate] .lib-featured-product__info > * { animation: lib-featured-product-rise linear both; animation-timeline: view(); animation-range: entry 0% entry 50%; } } } @keyframes lib-featured-product-rise { from { opacity: 0; transform: translateY(20px); } } @media (prefers-reduced-motion: reduce) { .lib-featured-product__add, .lib-featured-product__value, .lib-featured-product__thumb { transition: none; } .lib-featured-product__add:hover:not(:disabled) { transform: none; } } {% endstylesheet %} {% javascript %} if (!customElements.get('lib-featured-product')) { customElements.define( 'lib-featured-product', class extends HTMLElement { connectedCallback() { const data = this.querySelector('script[data-variants]'); this.form = this.querySelector('form'); if (!data || !this.form) return; try { this.variants = JSON.parse(data.textContent); } catch (error) { console.error('lib-featured-product: variant data could not be read', error); return; } this.cleanup = []; const listen = (target, type, fn) => { target.addEventListener(type, fn); this.cleanup.push(() => target.removeEventListener(type, fn)); }; this.idInput = this.querySelector('[data-variant-id]'); this.groups = [...this.querySelectorAll('[data-option]')]; this.slides = [...this.querySelectorAll('.lib-featured-product__slide[data-media-id]')]; this.thumbs = [...this.querySelectorAll('[data-show-index]')]; this.addButton = this.querySelector('[data-add]'); // Swap the plain variant menu for option buttons. const fallback = this.querySelector('[data-fallback]'); if (fallback && this.groups.length) { fallback.hidden = true; fallback.querySelector('select').disabled = true; this.idInput.disabled = false; this.groups.forEach((group) => { group.hidden = false; listen(group, 'change', () => this.update()); }); } const thumbList = this.querySelector('[data-thumbs]'); if (thumbList) thumbList.hidden = false; this.thumbs.forEach((thumb) => listen(thumb, 'click', () => this.showSlide(Number(thumb.dataset.showIndex)))); const qty = this.querySelector('.lib-featured-product__qty-input'); this.querySelectorAll('[data-step]').forEach((button) => { button.hidden = false; listen(button, 'click', () => { const next = Math.max(1, (parseInt(qty.value, 10) || 1) + Number(button.dataset.step)); qty.value = String(next); }); }); if (this.groups.length) this.update(); } disconnectedCallback() { (this.cleanup || []).forEach((fn) => fn()); this.cleanup = []; } selectedValues() { return this.groups.map((group) => group.querySelector('input:checked')?.value); } update() { const selected = this.selectedValues(); const matches = (variant, index, value) => variant.options.every((option, i) => (i === index ? option === value : option === selected[i])); // Mark every value that would lead to a sold-out or missing combination. this.groups.forEach((group, index) => { group.querySelectorAll('input').forEach((input) => { const variant = this.variants.find((v) => matches(v, index, input.value)); const soldOut = !variant || !variant.available; const choice = input.closest('.lib-featured-product__choice'); choice.toggleAttribute('data-sold-out', soldOut); choice.querySelector('[data-sold-out-text]').hidden = !soldOut; }); }); const variant = this.variants.find((v) => v.options.every((option, i) => option === selected[i])); const button = this.addButton; if (!variant) { button.disabled = true; button.textContent = button.dataset.unavailable; return; } this.idInput.value = variant.id; button.disabled = !variant.available; button.textContent = variant.available ? button.dataset.label : button.dataset.soldOut; const onSale = Boolean(variant.compare); const price = this.querySelector('[data-price]'); price.textContent = variant.price; price.classList.toggle('is-sale', onSale); const compare = this.querySelector('[data-compare]'); compare.textContent = variant.compare || ''; compare.hidden = !onSale; this.querySelector('[data-sale-label]').hidden = !onSale; this.querySelector('[data-was-label]').hidden = !onSale; this.querySelector('[data-badge-sale]').hidden = !onSale; this.querySelector('[data-badge-sold]').hidden = variant.available; if (variant.media !== null) { const index = this.slides.findIndex((slide) => slide.dataset.mediaId === String(variant.media)); if (index > -1) this.showSlide(index); } } showSlide(index) { this.slides.forEach((slide, i) => { slide.hidden = i !== index; }); this.thumbs.forEach((thumb, i) => { if (i === index) thumb.setAttribute('aria-current', 'true'); else thumb.removeAttribute('aria-current'); }); } }, ); } {% endjavascript %} {% schema %} { "name": "Lib · Featured product", "tag": "section", "class": "lib-section", "settings": [ { "type": "header", "content": "Product" }, { "type": "product", "id": "product", "label": "Product" }, { "type": "checkbox", "id": "show_vendor", "label": "Show vendor", "default": true }, { "type": "select", "id": "heading_tag", "label": "Product title tag", "info": "Use H1 only when this is the page's main heading.", "options": [ { "value": "h1", "label": "H1" }, { "value": "h2", "label": "H2" }, { "value": "h3", "label": "H3" }, { "value": "p", "label": "Paragraph" } ], "default": "h2" }, { "type": "select", "id": "heading_size", "label": "Product title size", "options": [ { "value": "small", "label": "Small" }, { "value": "medium", "label": "Medium" }, { "value": "large", "label": "Large" } ], "default": "medium" }, { "type": "checkbox", "id": "show_description", "label": "Show product description", "default": true }, { "type": "checkbox", "id": "show_quantity", "label": "Show quantity selector", "default": true }, { "type": "header", "content": "Gallery" }, { "type": "checkbox", "id": "show_thumbnails", "label": "Show thumbnails", "default": true }, { "type": "select", "id": "media_ratio", "label": "Image shape", "options": [ { "value": "adapt", "label": "Adapt to first image" }, { "value": "square", "label": "Square" }, { "value": "portrait", "label": "Portrait" }, { "value": "landscape", "label": "Landscape" } ], "default": "square" }, { "type": "range", "id": "corner_radius", "label": "Corner radius", "min": 0, "max": 32, "step": 2, "unit": "px", "default": 12 }, { "type": "text", "id": "details_label", "label": "Details link label", "info": "Links to the product page. Leave empty to hide.", "default": "View full details" }, { "type": "select", "id": "details_style", "label": "Details link style", "options": [ { "value": "primary", "label": "Solid" }, { "value": "outline", "label": "Outline" }, { "value": "text", "label": "Text link" } ], "default": "text" }, { "type": "checkbox", "id": "details_new_tab", "label": "Open details link in a new tab", "default": false }, { "type": "header", "content": "Shopper-facing words" }, { "type": "text", "id": "button_label", "label": "Add to cart button", "default": "Add to cart" }, { "type": "text", "id": "sold_out_label", "label": "Sold out", "default": "Sold out" }, { "type": "text", "id": "unavailable_label", "label": "Unavailable combination", "default": "Unavailable" }, { "type": "text", "id": "sale_badge_label", "label": "Sale badge", "default": "Sale" }, { "type": "text", "id": "sale_price_label", "label": "Sale price (screen readers)", "default": "Sale price" }, { "type": "text", "id": "regular_price_label", "label": "Regular price (screen readers)", "default": "Regular price" }, { "type": "text", "id": "quantity_label", "label": "Quantity (screen readers)", "default": "Quantity" }, { "type": "text", "id": "decrease_label", "label": "Decrease quantity (screen readers)", "default": "Decrease quantity" }, { "type": "text", "id": "increase_label", "label": "Increase quantity (screen readers)", "default": "Increase quantity" }, { "type": "text", "id": "thumbnail_label", "label": "Thumbnail button (screen readers)", "info": "The image number is added, e.g. \"Show image 2\".", "default": "Show image" }, { "type": "header", "content": "Layout" }, { "type": "select", "id": "media_position", "label": "Gallery position on desktop", "options": [ { "value": "left", "label": "Left" }, { "value": "right", "label": "Right" } ], "default": "left" }, { "type": "select", "id": "media_width", "label": "Gallery width on desktop", "options": [ { "value": "half", "label": "Half" }, { "value": "wide", "label": "Wide" } ], "default": "half" }, { "type": "select", "id": "mobile_order", "label": "Order on mobile", "options": [ { "value": "media_first", "label": "Gallery first" }, { "value": "info_first", "label": "Product info first" } ], "default": "media_first" }, { "type": "select", "id": "section_width", "label": "Width", "options": [ { "value": "page", "label": "Page width" }, { "value": "full", "label": "Full width" } ], "default": "page" }, { "type": "select", "id": "text_alignment", "label": "Text alignment on desktop", "options": [ { "value": "left", "label": "Left" }, { "value": "center", "label": "Center" } ], "default": "left" }, { "type": "select", "id": "text_alignment_mobile", "label": "Text alignment on mobile", "options": [ { "value": "left", "label": "Left" }, { "value": "center", "label": "Center" } ], "default": "left" }, { "type": "header", "content": "Colors" }, { "type": "color", "id": "color_bg", "label": "Background", "default": "#FBF8F4" }, { "type": "color", "id": "color_text", "label": "Text", "default": "#231F1B" }, { "type": "color", "id": "color_accent", "label": "Add to cart button, sale price and badge", "default": "#7C2D12" }, { "type": "color", "id": "color_accent_text", "label": "Text on button and sale badge", "default": "#FFFFFF" }, { "type": "color", "id": "color_border", "label": "Borders", "default": "#D9D2C8" }, { "type": "header", "content": "Spacing, visibility and motion" }, { "type": "range", "id": "padding_top", "label": "Top padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 }, { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 }, { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 40 }, { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 }, { "type": "select", "id": "show_on", "label": "Show on", "options": [ { "value": "all", "label": "All devices" }, { "value": "desktop", "label": "Desktop only" }, { "value": "mobile", "label": "Mobile only" } ], "default": "all" }, { "type": "text", "id": "anchor_id", "label": "Anchor ID", "info": "Optional. Link to this section with #your-id." }, { "type": "checkbox", "id": "animate", "label": "Fade in on scroll", "info": "Only in browsers that support scroll-driven animations; never when reduced motion is on.", "default": false } ], "presets": [ { "name": "Lib · Featured product" } ] } {% endschema %}