Template
Featured collection grid
A responsive product grid section with configurable columns, an optional heading and a "view all" link.
Save as sections/featured-collection-grid.liquid. The grid uses CSS grid with a container query, so it reflows correctly inside narrow page templates as well as full-width layouts — which is how Harbor Home lays out its own collection sections.
What to change
- The card markup, if your theme has its own product-card snippet — replace the inner markup with {% render 'card-product', card_product: product %}.
- The image aspect ratio, set on .collection-grid__media.
- The maximum product count, capped at 12 in the schema.
Code
Copy a single file, or download all 3 as an archive. Duplicate your theme before pasting into a live store.
template.liquidLiquid {% comment %} Featured collection grid — sections/featured-collection-grid.liquid {% endcomment %} {%- liquid assign collection = collections[section.settings.collection] assign limit = section.settings.products_to_show -%} <section class="collection-grid" style="--collection-columns: {{ section.settings.columns }};"> {%- if section.settings.heading != blank -%} <div class="collection-grid__header"> <h2 class="collection-grid__heading">{{ section.settings.heading | escape }}</h2> {%- if section.settings.show_view_all and collection != blank -%} <a class="collection-grid__view-all" href="{{ collection.url }}"> View all </a> {%- endif -%} </div> {%- endif -%} {%- if collection.products_count > 0 -%} <ul class="collection-grid__list" role="list"> {%- for product in collection.products limit: limit -%} <li class="collection-grid__item"> <a class="collection-grid__card" href="{{ product.url }}"> <div class="collection-grid__media"> {%- if product.featured_media -%} {{ product.featured_media | image_url: width: 800 | image_tag: loading: 'lazy', sizes: '(min-width: 990px) 25vw, 50vw', widths: '200, 400, 600, 800', alt: product.featured_media.alt | default: product.title }} {%- endif -%} </div> <p class="collection-grid__title">{{ product.title }}</p> <p class="collection-grid__price">{{ product.price | money }}</p> </a> </li> {%- endfor -%} </ul> {%- else -%} <p class="collection-grid__empty">Select a collection with products to populate this section.</p> {%- endif -%} </section> {% schema %} { "name": "Featured collection grid", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Featured products" }, { "type": "collection", "id": "collection", "label": "Collection" }, { "type": "range", "id": "products_to_show", "label": "Products to show", "min": 2, "max": 12, "step": 1, "default": 8 }, { "type": "range", "id": "columns", "label": "Columns on desktop", "min": 2, "max": 5, "step": 1, "default": 4 }, { "type": "checkbox", "id": "show_view_all", "label": "Show \"View all\" link", "default": true } ], "presets": [{ "name": "Featured collection grid" }] } {% endschema %}template.cssCSS .collection-grid { container-type: inline-size; padding-block: 3rem; } .collection-grid__header { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 1rem; margin-bottom: 1.5rem; } .collection-grid__heading { margin: 0; font-size: 1.75rem; line-height: 1.2; } .collection-grid__view-all { font-size: 0.875rem; text-decoration: underline; text-underline-offset: 0.2em; } .collection-grid__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.5rem 1rem; margin: 0; padding: 0; } @container (min-width: 48rem) { .collection-grid__list { grid-template-columns: repeat(var(--collection-columns, 4), minmax(0, 1fr)); } } .collection-grid__card { display: grid; gap: 0.375rem; color: inherit; text-decoration: none; } .collection-grid__media { aspect-ratio: 3 / 4; overflow: hidden; background: rgb(0 0 0 / 0.04); } .collection-grid__media img { width: 100%; height: 100%; object-fit: cover; } .collection-grid__title, .collection-grid__price { margin: 0; font-size: 0.9375rem; } .collection-grid__price { color: rgb(0 0 0 / 0.65); } .collection-grid__empty { margin: 0; color: rgb(0 0 0 / 0.65); }template.jsJavaScript (() => { // Progressive enhancement only: reveal cards as they scroll into view. // The grid is fully rendered and navigable with JavaScript disabled. function init() { const items = document.querySelectorAll('.collection-grid__item'); if (!items.length) return; if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; if (!('IntersectionObserver' in window)) return; const observer = new IntersectionObserver( (entries) => { for (const entry of entries) { if (!entry.isIntersecting) continue; entry.target.classList.add('is-visible'); observer.unobserve(entry.target); } }, { rootMargin: '0px 0px -10% 0px' }, ); items.forEach((item) => observer.observe(item)); } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init, { once: true }); } else { init(); } document.addEventListener('shopify:section:load', init); })();