{%- comment -%} MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections {%- endcomment -%} {%- comment -%} Complementary products: "pairs well with" cards on a product page, from Shopify's own product recommendations with the complementary intent. You choose the products per product in Shopify's free Search & Discovery app; the section asks the store's recommendations endpoint for them after the page loads (Section Rendering API) and stays hidden when there are none. Cards show price, badges and an optional quick add (a plain product form for single-variant products). Depends on: snippets/lib-product-card.liquid, snippets/lib-image.liquid {%- endcomment -%} {%- liquid assign s = section.settings assign heading_tag = s.heading_tag | default: 'h2' assign card_tag = 'h3' if heading_tag == 'h3' or heading_tag == 'p' assign card_tag = 'h4' endif assign cols = s.columns | plus: 0 assign cols_m = s.columns_mobile | plus: 0 assign img_vw = 100 | divided_by: cols assign img_sizes = '(min-width: 990px) ' | append: img_vw | append: 'vw, (min-width: 750px) 33vw, 50vw' if s.layout == 'list' assign img_sizes = '120px' endif assign has_results = false if recommendations.products_count > 0 assign has_results = true endif -%} {% stylesheet %} .lib-compl { display: block; background-color: var(--lib-bg); background-image: var(--lib-bg-image, none); color: var(--lib-text); padding: var(--lib-pt) 1rem var(--lib-pb); } .lib-compl[hidden] { display: none; } .lib-compl__inner { max-width: 1200px; margin: 0 auto; } .lib-compl--full .lib-compl__inner { max-width: none; } .lib-compl[data-layout='list'] .lib-compl__inner { max-width: 40rem; } @media (max-width: 749px) { .lib-compl { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); } .lib-compl[data-show='desktop'] { display: none; } } @media (min-width: 750px) { .lib-compl[data-show='mobile'] { display: none; } } .lib-compl__header { margin-bottom: clamp(1.25rem, 3vw, 2rem); } .lib-compl[data-layout='list'] .lib-compl__header { margin-bottom: 1rem; } .lib-compl__heading { margin: 0; font-size: clamp(1.5rem, 2.6vw, 2.125rem); line-height: 1.15; letter-spacing: -0.02em; text-wrap: balance; } .lib-compl__heading--small { font-size: clamp(1.0625rem, 1.5vw, 1.25rem); } .lib-compl__heading--large { font-size: clamp(2rem, 4vw, 3rem); } .lib-compl__text { margin-top: 0.5rem; font-size: 1rem; line-height: 1.6; opacity: 0.85; } .lib-compl__text > :first-child { margin-top: 0; } .lib-compl__text > :last-child { margin-bottom: 0; } .lib-compl__header[data-align='center'] { text-align: center; } @media (max-width: 749px) { .lib-compl__header[data-align-m='left'] { text-align: left; } .lib-compl__header[data-align-m='center'] { text-align: center; } } .lib-compl__list { display: grid; grid-template-columns: repeat(var(--lib-cols), minmax(0, 1fr)); gap: clamp(1rem, 2vw, 1.5rem); margin: 0; padding: 0; list-style: none; } .lib-compl__item { display: flex; min-width: 0; } @media (max-width: 749px) { .lib-compl__list { grid-template-columns: repeat(var(--lib-cols-m), minmax(0, 1fr)); } } /* List: a compact row per product, for the area under the buy box. */ .lib-compl[data-layout='list'] .lib-compl__list { grid-template-columns: 1fr; gap: 0.75rem; } .lib-compl[data-layout='list'] .lib-card { flex-direction: row; align-items: center; gap: 1rem; padding: 0.625rem; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--lib-text) 12%, transparent); } .lib-compl[data-layout='list'] .lib-card__media { flex: none; width: clamp(4.5rem, 18vw, 6rem); border-radius: calc(var(--lib-radius-card) * 0.66); } .lib-compl[data-layout='list'] .lib-card__body { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 0.2rem 1rem; padding: 0; } .lib-compl[data-layout='list'] .lib-card__body > :not(.lib-card__cta) { grid-column: 1; } .lib-compl[data-layout='list'] .lib-card__cta { grid-column: 2; grid-row: 1 / span 3; margin: 0; padding: 0; } .lib-compl[data-layout='list'] .lib-card__add { width: auto; min-width: 6.5rem; } .lib-compl[data-layout='list'] .lib-card__badge { display: none; } @media (max-width: 479px) { .lib-compl[data-layout='list'] .lib-card__body { grid-template-columns: 1fr; } .lib-compl[data-layout='list'] .lib-card__cta { grid-column: 1; grid-row: auto; padding-top: 0.4rem; } } .lib-compl__note { margin: 1rem 0 0; font-size: 0.875rem; opacity: 0.75; } @media (prefers-reduced-motion: no-preference) { .lib-compl[data-animate][data-loaded] .lib-compl__item { animation: lib-compl-in 0.5s cubic-bezier(0.2, 0.7, 0.2, 1) both; } } @keyframes lib-compl-in { from { opacity: 0; transform: translateY(12px); } } {% endstylesheet %} {% javascript %} (() => { if (customElements.get('lib-complementary-products')) return; class LibComplementaryProducts extends HTMLElement { connectedCallback() { const url = this.dataset.url; if (!url || this.dataset.requested) return; this.dataset.requested = 'true'; // Load only when the section comes near the screen: product pages stay light. if (!('IntersectionObserver' in window)) { this.load(url); return; } const observer = new IntersectionObserver( (entries) => { if (!entries.some((e) => e.isIntersecting)) return; observer.disconnect(); this.load(url); }, {rootMargin: '0px 0px 400px 0px'}, ); // A hidden element never intersects, so watch its parent section instead. observer.observe(this.parentElement || this); } async load(url) { try { const response = await fetch(url); if (!response.ok) throw new Error(`recommendations answered ${response.status}`); const doc = new DOMParser().parseFromString(await response.text(), 'text/html'); const results = doc.querySelector('.lib-compl [data-results]'); if (!results || !results.querySelector('.lib-card')) return; this.querySelector('[data-results]').replaceWith(results); this.toggleAttribute('data-loaded', true); this.hidden = false; } catch (error) { // No recommendations is a normal state; the section just stays hidden. console.warn('Complementary products could not be loaded.', error); } } } customElements.define('lib-complementary-products', LibComplementaryProducts); })(); {% endjavascript %} {% schema %} { "name": "Lib · Complementary", "tag": "section", "class": "lib-section", "enabled_on": { "templates": ["product"] }, "settings": [ { "type": "paragraph", "content": "Choose each product's complementary products in Shopify's Search & Discovery app. The section stays hidden on products without any." }, { "type": "header", "content": "Content" }, { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Pairs well with" }, { "type": "select", "id": "heading_tag", "label": "Heading 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": "Heading size", "options": [ { "value": "small", "label": "Small" }, { "value": "medium", "label": "Medium" }, { "value": "large", "label": "Large" } ], "default": "medium" }, { "type": "richtext", "id": "text", "label": "Intro text" }, { "type": "header", "content": "Products" }, { "type": "range", "id": "products_to_show", "label": "Products to show", "min": 1, "max": 10, "step": 1, "default": 4 }, { "type": "select", "id": "layout", "label": "Layout", "info": "List suits the area under the buy box; grid suits a full-width row.", "options": [ { "value": "grid", "label": "Grid" }, { "value": "list", "label": "List" } ], "default": "grid" }, { "type": "select", "id": "image_ratio", "label": "Image shape", "options": [ { "value": "square", "label": "Square" }, { "value": "portrait", "label": "Portrait" }, { "value": "tall", "label": "Tall" }, { "value": "landscape", "label": "Landscape" } ], "default": "square" }, { "type": "select", "id": "card_style", "label": "Card style", "options": [ { "value": "plain", "label": "Plain" }, { "value": "card", "label": "Card" } ], "default": "plain" }, { "type": "range", "id": "card_radius", "label": "Corner radius", "min": 0, "max": 24, "step": 2, "unit": "px", "default": 12 }, { "type": "checkbox", "id": "show_vendor", "label": "Show vendor", "default": false }, { "type": "checkbox", "id": "show_quick_add", "label": "Show quick add", "info": "Products with options link to their page instead.", "default": true }, { "type": "text", "id": "quick_add_label", "label": "Quick add button", "default": "Add to cart" }, { "type": "text", "id": "choose_label", "label": "Link for products with options", "default": "Choose options" }, { "type": "text", "id": "sale_label", "label": "Sale badge", "default": "Sale" }, { "type": "text", "id": "sold_out_label", "label": "Sold out badge", "default": "Sold out" }, { "type": "text", "id": "sale_price_label", "label": "Sale price label (screen readers)", "default": "Sale price" }, { "type": "text", "id": "regular_price_label", "label": "Regular price label (screen readers)", "default": "Regular price" }, { "type": "header", "content": "Layout" }, { "type": "range", "id": "columns", "label": "Columns on desktop (grid)", "min": 2, "max": 5, "step": 1, "default": 4 }, { "type": "range", "id": "columns_mobile", "label": "Columns on mobile (grid)", "min": 1, "max": 2, "step": 1, "default": 2 }, { "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": "Heading alignment on desktop", "options": [ { "value": "left", "label": "Left" }, { "value": "center", "label": "Center" } ], "default": "left" }, { "type": "select", "id": "text_alignment_mobile", "label": "Heading 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": "#FFFFFF" }, { "type": "color_background", "id": "color_bg_gradient", "label": "Background gradient", "info": "Optional. Covers the background color." }, { "type": "color", "id": "color_text", "label": "Text", "default": "#1F1B17" }, { "type": "color", "id": "color_accent", "label": "Accent (buttons, badges)", "default": "#7A5A3A" }, { "type": "color", "id": "color_accent_text", "label": "Text on accent", "default": "#FFFFFF" }, { "type": "color", "id": "color_card", "label": "Card background", "default": "#FAF6F1" }, { "type": "header", "content": "Spacing and visibility" }, { "type": "range", "id": "padding_top", "label": "Top padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 56 }, { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 56 }, { "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": 40 }, { "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": "header", "content": "Motion" }, { "type": "checkbox", "id": "animate", "label": "Fade cards in as they load", "info": "Never when reduced motion is on.", "default": true } ], "presets": [{ "name": "Lib · Complementary" }] } {% endschema %}