Shopify Liquid
Snippets

8 copy-paste Liquid snippets we ship in real themes: section schema, free-shipping bar, metafields with fallbacks, responsive images, sale and low-stock badges, SEO breadcrumbs and safe JSON for JavaScript. Every snippet follows Online Store 2.0 architecture. MIT licensed.

Snippet library

Copy-paste Shopify Liquid code for Online Store 2.0 themes

Eight production patterns: a section skeleton with blocks and presets, a cart free-shipping bar, metafields with fallbacks, responsive images, sale and low-stock badges, SEO breadcrumbs with schema, and a safe product-to-JavaScript handoff. Filter by topic, copy, paste into your theme.

Online Store 2.0 section skeleton with blocks

sections/mg-feature-grid.liquidsectionstheme

Minimal section with settings, repeatable blocks and presets so it appears in the theme editor. Start every custom Shopify section from here.

{%- comment -%} sections/mg-feature-grid.liquid {%- endcomment -%}
<section class="mg-feature-grid" id="shopify-section-{{ section.id }}">
  {%- if section.settings.heading != blank -%}
    <h2 class="mg-feature-grid__title">{{ section.settings.heading | escape }}</h2>
  {%- endif -%}
  <div class="mg-feature-grid__items">
    {%- for block in section.blocks -%}
      <div class="mg-feature-grid__item" {{ block.shopify_attributes }}>
        {%- if block.settings.icon != blank -%}
          {{ block.settings.icon | image_url: width: 96 | image_tag: loading: 'lazy', widths: '48, 96', alt: block.settings.title }}
        {%- endif -%}
        <h3>{{ block.settings.title | escape }}</h3>
        <div class="rte">{{ block.settings.text }}</div>
      </div>
    {%- endfor -%}
  </div>
</section>

{% schema %}
{
  "name": "Feature grid",
  "tag": "section",
  "class": "section",
  "settings": [
    { "type": "text", "id": "heading", "label": "Heading", "default": "Why shop with us" }
  ],
  "blocks": [
    {
      "type": "feature",
      "name": "Feature",
      "limit": 6,
      "settings": [
        { "type": "image_picker", "id": "icon", "label": "Icon" },
        { "type": "text", "id": "title", "label": "Title", "default": "Free shipping" },
        { "type": "richtext", "id": "text", "label": "Text", "default": "<p>On all orders over $50.</p>" }
      ]
    }
  ],
  "presets": [{ "name": "Feature grid", "blocks": [{ "type": "feature" }, { "type": "feature" }, { "type": "feature" }] }]
}
{% endschema %}

Free shipping progress bar for the cart

snippets/mg-shipping-bar.liquidcartcro

Shows how much is left to unlock free shipping. Threshold is a theme setting in cents-aware currency; call it with {% render 'mg-shipping-bar', threshold: settings.free_shipping_threshold %}. A classic CRO win for AOV.

{%- comment -%} snippets/mg-shipping-bar.liquid — threshold in store currency units {%- endcomment -%}
{%- assign threshold_cents = threshold | times: 100 -%}
{%- assign remaining = threshold_cents | minus: cart.total_price -%}
{%- assign percent = cart.total_price | times: 100 | divided_by: threshold_cents | at_most: 100 -%}
<div class="mg-shipping-bar" role="status" aria-live="polite">
  {%- if remaining > 0 -%}
    <p class="mg-shipping-bar__text">Add {{ remaining | money }} more for <strong>free shipping</strong></p>
  {%- else -%}
    <p class="mg-shipping-bar__text">🎉 You've unlocked <strong>free shipping</strong></p>
  {%- endif -%}
  <div class="mg-shipping-bar__track"><div class="mg-shipping-bar__fill" style="width: {{ percent }}%"></div></div>
</div>

Product metafield with safe fallback

snippets/mg-metafield.liquidproductmetafields

Renders a metafield only when the definition exists and has a value; falls back to a default. Works for single-line text, rich text and lists.

{%- comment -%} Single-line text or number {%- endcomment -%}
{%- assign material = product.metafields.specs.material -%}
{%- if material != blank -%}
  <dt>Material</dt><dd>{{ material.value | escape }}</dd>
{%- else -%}
  <dt>Material</dt><dd>See product description</dd>
{%- endif -%}

{%- comment -%} Rich text (metafield_tag renders proper HTML) {%- endcomment -%}
{%- if product.metafields.specs.care_guide != blank -%}
  <div class="rte">{{ product.metafields.specs.care_guide | metafield_tag }}</div>
{%- endif -%}

{%- comment -%} List of single-line text {%- endcomment -%}
{%- if product.metafields.specs.features.value.size > 0 -%}
  <ul>
    {%- for feature in product.metafields.specs.features.value -%}
      <li>{{ feature | escape }}</li>
    {%- endfor -%}
  </ul>
{%- endif -%}

Responsive image with srcset and lazy loading

snippets/mg-image.liquidperformancetheme

Uses image_url + image_tag so Shopify serves the right size per viewport; first-fold images get loading: eager and fetchpriority for better LCP. Part of every performance audit we run.

{%- comment -%} {% render 'mg-image', image: product.featured_image, sizes: '(min-width: 990px) 50vw, 100vw', eager: true %} {%- endcomment -%}
{%- if image != blank -%}
  {%- assign loading = 'lazy' -%}
  {%- assign priority = 'auto' -%}
  {%- if eager -%}{%- assign loading = 'eager' -%}{%- assign priority = 'high' -%}{%- endif -%}
  {{ image
    | image_url: width: 1800
    | image_tag:
        widths: '360, 540, 720, 900, 1080, 1296, 1512, 1800',
        sizes: sizes | default: '100vw',
        loading: loading,
        fetchpriority: priority,
        alt: image.alt | default: product.title | escape
  }}
{%- endif -%}

Sale badge with discount percentage

snippets/mg-sale-badge.liquidproductcro

Computes the discount from compare_at_price for the selected variant and only renders when there is a real saving. Use money_without_trailing_zeros for cleaner prices.

{%- assign v = product.selected_or_first_available_variant -%}
{%- if v.compare_at_price > v.price -%}
  {%- assign saving = v.compare_at_price | minus: v.price -%}
  {%- assign percent = saving | times: 100 | divided_by: v.compare_at_price -%}
  <span class="mg-badge mg-badge--sale">Save {{ percent }}%</span>
  <s class="mg-price__compare">{{ v.compare_at_price | money_without_trailing_zeros }}</s>
{%- endif -%}
<span class="mg-price">{{ v.price | money_without_trailing_zeros }}</span>

Low-stock and sold-out badges

snippets/mg-stock-badge.liquidproductcro

Urgency badge that respects inventory policy: sold out when unavailable, "only N left" under a threshold, silent otherwise. Threshold defaults to 5.

{%- assign v = product.selected_or_first_available_variant -%}
{%- assign low = low_threshold | default: 5 -%}
{%- if v.available == false -%}
  <span class="mg-badge mg-badge--soldout">Sold out</span>
{%- elsif v.inventory_management == 'shopify' and v.inventory_policy == 'deny' and v.inventory_quantity <= low -%}
  <span class="mg-badge mg-badge--low">Only {{ v.inventory_quantity }} left</span>
{%- endif -%}

Hand product data to JavaScript safely

sections/main-product.liquidproductjavascript

Emit variant data as JSON in a <script type="application/json"> tag instead of inline JS — safe against quotes, cacheable, and easy to read in your variant picker.

<script type="application/json" id="mg-product-{{ section.id }}">
  {{ product | json }}
</script>
<script type="application/json" id="mg-variants-{{ section.id }}">
  {{ product.variants | json }}
</script>

<script>
  (function () {
    var product = JSON.parse(document.getElementById('mg-product-{{ section.id }}').textContent);
    var variants = JSON.parse(document.getElementById('mg-variants-{{ section.id }}').textContent);
    // Example: find the variant matching selected options
    function findVariant(options) {
      return variants.find(function (v) {
        return v.options.every(function (o, i) { return o === options[i]; });
      });
    }
    window.mgProduct = { product: product, variants: variants, findVariant: findVariant };
  })();
</script>
Using these snippets

How to add Liquid snippets to a Shopify theme

  • Sections go in sections/ and need a {% schema %} block to appear in the theme editor.
  • Snippets go in snippets/ and are rendered with {% render 'file-name' %}. Pass variables explicitly — render does not inherit scope.
  • Work in a duplicate theme or with Shopify CLI and Git; never edit the live theme directly.
  • Metafield definitions must exist in Settings → Custom data before product.metafields.namespace.key returns a value.

Need a section that doesn't exist yet? Read the custom Shopify sections guide or hire our Shopify section developers. Weighing Liquid against a headless build? See Shopify Hydrogen vs Liquid. Planning a replatform first? Start with the Shopify migration checklist.

Liquid performance rules we follow in every snippet

  • No inline JavaScript in loops. Data goes into a single application/json script per section; behaviour lives in a deferred file.
  • Images via image_url + image_tag with explicit widths and sizes, lazy by default, eager with fetchpriority="high" only for the first-fold image — the single biggest LCP win on Shopify product pages.
  • Whitespace control ({%- and -%}) on every tag so the rendered HTML stays small and predictable.
  • Escape everything merchant-editable with | escape; use | json when handing values to JavaScript.
  • Guard metafields with != blank and check .value.size on lists so unset definitions never print empty markup.

These are the same rules behind the 90+ Lighthouse targets on our custom Shopify theme development projects and the Core Web Vitals audits we run for existing stores.

FAQ

Shopify Liquid FAQ

What is Shopify Liquid?

Liquid is Shopify's open-source template language. Theme files combine HTML with Liquid objects ({{ product.title }}), tags ({% if %}, {% for %}) and filters (| money) that Shopify renders on the server before sending the page to the browser.

What is the difference between a Shopify section and a snippet?

Sections live in sections/, have a {% schema %} block and appear in the theme editor where merchants add, reorder and configure them. Snippets live in snippets/, are included with {% render %} and are reusable fragments with no editor settings of their own.

Are these snippets compatible with Online Store 2.0 themes?

Yes. They use current Shopify APIs — image_url and image_tag filters, metafield definitions, section schema with blocks and presets — and work in Dawn-based and custom Online Store 2.0 themes.

Can I use these Liquid snippets in a client project?

Yes. All snippets are MIT licensed. Test in a duplicate theme, rename classes to match your theme and keep an eye on Shopify's changelog for deprecated filters.

Do you build custom Shopify sections?

Yes. Custom Shopify sections and full theme development are core Mgroup services — every section ships with editor controls, schema docs and Core Web Vitals-safe markup.

Shopify Section Partner

Ready to give your editor real superpowers?

Talk to Mgroup about custom Shopify sections — designed for your brand, built on Online Store 2.0, easy to edit, and fast in production.