The average Shopify store I audit has 15-20 apps installed. Each one adds JavaScript to every page load, costs $10-50/month, and creates a dependency on a third party that could change pricing, break with theme updates, or shut down entirely.
Here’s the uncomfortable truth: most of those apps can be replaced with 20-50 lines of Liquid code. No recurring fees. No external scripts. No dependencies. Just clean, fast, server-rendered HTML that you fully control.
These 15 snippets come from real production stores I’ve built and optimized over 12 years. Every one is copy-paste ready with working code. For the full context on Liquid development patterns, start with my Shopify Liquid development guide.
Why Replace Apps with Custom Liquid Code?
Every installed Shopify app has a cost beyond the monthly fee.
Performance impact. Each app typically adds 50-200KB of JavaScript that loads on every page. Three apps can add 500ms+ to your load time. On the WD Electronics audit, we traced 2.3 seconds of mobile load time directly to app scripts that could have been replaced with Liquid.
Monthly cost. A typical app stack for a DTC store — reviews, upsells, trust badges, announcement bar, countdown timer, size chart, free shipping bar — runs $200-500/month. That’s $2,400-6,000/year for functionality that Liquid handles natively.
Maintenance risk. Apps break after theme updates. They conflict with each other. They inject CSS that overrides your design. When an app company gets acquired or shuts down, you’re scrambling to replace critical functionality.
Full control. Custom Liquid means you control the markup, the styling, the behavior, and the performance. No black-box JavaScript doing things you can’t inspect. For deep performance optimization patterns, see my Liquid loop optimization guide.
Store Design and UX Snippets
1. Announcement Bar with Auto-Dismiss
Replaces: Hextom, Starter, and similar banner apps ($0-15/month).
{% comment %} sections/announcement-bar.liquid {% endcomment %}
{%- if section.settings.text != blank -%}
<div class="announcement-bar" id="announcement-bar"
style="background: {{ section.settings.bg_color }}; color: {{ section.settings.text_color }};">
<div class="announcement-bar__inner">
{%- if section.settings.link != blank -%}
<a href="{{ section.settings.link }}" class="announcement-bar__link">
{{ section.settings.text }}
</a>
{%- else -%}
<p class="announcement-bar__text">{{ section.settings.text }}</p>
{%- endif -%}
{%- if section.settings.dismissable -%}
<button class="announcement-bar__close" aria-label="Dismiss" onclick="
this.parentElement.parentElement.style.display='none';
sessionStorage.setItem('announcement-dismissed','1');
">×</button>
{%- endif -%}
</div>
</div>
{%- if section.settings.dismissable -%}
<script>
if (sessionStorage.getItem('announcement-dismissed') === '1') {
document.getElementById('announcement-bar').style.display = 'none';
}
</script>
{%- endif -%}
{%- endif -%}
<style>
.announcement-bar { padding: 0.6rem 1rem; text-align: center; font-size: 0.85rem; font-weight: 600; }
.announcement-bar__inner { display: flex; align-items: center; justify-content: center; gap: 1rem; max-width: 1200px; margin: 0 auto; }
.announcement-bar__link { color: inherit; text-decoration: underline; }
.announcement-bar__close { background: none; border: none; color: inherit; font-size: 1.2rem; cursor: pointer; padding: 0 0.5rem; opacity: 0.7; }
.announcement-bar__close:hover { opacity: 1; }
</style>
{% schema %}
{
"name": "Announcement Bar",
"settings": [
{ "type": "text", "id": "text", "label": "Text", "default": "Free shipping on orders over $75" },
{ "type": "url", "id": "link", "label": "Link (optional)" },
{ "type": "color", "id": "bg_color", "label": "Background", "default": "#5C6AC4" },
{ "type": "color", "id": "text_color", "label": "Text color", "default": "#FFFFFF" },
{ "type": "checkbox", "id": "dismissable", "label": "Allow dismiss", "default": true }
],
"presets": [{ "name": "Announcement Bar" }]
}
{% endschema %}
Uses sessionStorage so the dismissal persists for the browser session but reappears on the next visit.
2. Countdown Timer
Replaces: Countdown timer apps ($5-15/month).
{% comment %} snippets/countdown-timer.liquid {% endcomment %}
{% comment %} Usage: {% render 'countdown-timer', end_date: '2026-04-15T23:59:59' %} {% endcomment %}
<div class="countdown" data-end="{{ end_date }}">
<div class="countdown__unit">
<span class="countdown__number" data-days>00</span>
<span class="countdown__label">Days</span>
</div>
<div class="countdown__unit">
<span class="countdown__number" data-hours>00</span>
<span class="countdown__label">Hours</span>
</div>
<div class="countdown__unit">
<span class="countdown__number" data-minutes>00</span>
<span class="countdown__label">Min</span>
</div>
<div class="countdown__unit">
<span class="countdown__number" data-seconds>00</span>
<span class="countdown__label">Sec</span>
</div>
</div>
<script>
(function() {
var el = document.querySelector('.countdown[data-end]');
if (!el) return;
var end = new Date(el.dataset.end).getTime();
function tick() {
var now = Date.now();
var diff = Math.max(0, end - now);
el.querySelector('[data-days]').textContent = String(Math.floor(diff / 86400000)).padStart(2, '0');
el.querySelector('[data-hours]').textContent = String(Math.floor((diff % 86400000) / 3600000)).padStart(2, '0');
el.querySelector('[data-minutes]').textContent = String(Math.floor((diff % 3600000) / 60000)).padStart(2, '0');
el.querySelector('[data-seconds]').textContent = String(Math.floor((diff % 60000) / 1000)).padStart(2, '0');
if (diff > 0) requestAnimationFrame(tick);
}
tick();
})();
</script>
<style>
.countdown { display: flex; gap: 1rem; justify-content: center; }
.countdown__unit { text-align: center; min-width: 60px; }
.countdown__number { display: block; font-size: 2rem; font-weight: 800; line-height: 1; }
.countdown__label { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; opacity: 0.7; }
</style>
3. Trust Badges Below Add-to-Cart
Replaces: Trust badge apps ($0-10/month).
{% comment %} snippets/trust-badges.liquid {% endcomment %}
<div class="trust-strip">
<div class="trust-strip__item">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
<span>Secure Checkout</span>
</div>
<div class="trust-strip__item">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="1" y="3" width="15" height="13"/><polygon points="16 8 20 8 23 11 23 16 16 16 16 8"/><circle cx="5.5" cy="18.5" r="2.5"/><circle cx="18.5" cy="18.5" r="2.5"/></svg>
<span>Free Shipping $75+</span>
</div>
<div class="trust-strip__item">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/></svg>
<span>30-Day Returns</span>
</div>
</div>
<style>
.trust-strip { display: flex; gap: 1.5rem; justify-content: center; padding: 1rem 0; margin-top: 1rem; border-top: 1px solid var(--color-border, #e5e5e5); }
.trust-strip__item { display: flex; align-items: center; gap: 0.4rem; font-size: 0.8rem; font-weight: 500; color: var(--color-text-muted, #666); }
.trust-strip__item svg { flex-shrink: 0; opacity: 0.7; }
</style>
Place this snippet right after your add-to-cart form with {% render 'trust-badges' %}. Customize the icons and text to match your store’s guarantees.
4. Custom Size Chart via Metafields
Replaces: Size chart apps ($5-10/month).
{% comment %} snippets/size-chart.liquid {% endcomment %}
{% comment %} Requires: product metafield "custom.size_chart" of type JSON {% endcomment %}
{%- if product.metafields.custom.size_chart != blank -%}
{%- assign chart = product.metafields.custom.size_chart.value -%}
<button class="size-chart-trigger" onclick="document.getElementById('size-chart-modal').showModal()">
Size Guide
</button>
<dialog id="size-chart-modal" class="size-chart-modal">
<div class="size-chart-modal__inner">
<div class="size-chart-modal__header">
<h3>Size Guide</h3>
<button onclick="this.closest('dialog').close()" aria-label="Close">×</button>
</div>
<div class="size-chart-modal__body">
<table class="size-chart-table">
<thead>
<tr>
{%- for header in chart.headers -%}
<th>{{ header }}</th>
{%- endfor -%}
</tr>
</thead>
<tbody>
{%- for row in chart.rows -%}
<tr>
{%- for cell in row -%}
<td>{{ cell }}</td>
{%- endfor -%}
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
</div>
</dialog>
<style>
.size-chart-trigger { background: none; border: none; text-decoration: underline; cursor: pointer; font-size: 0.85rem; color: var(--color-primary, #5C6AC4); padding: 0; }
.size-chart-modal { border: none; border-radius: 12px; padding: 0; max-width: 600px; width: 90%; }
.size-chart-modal::backdrop { background: rgba(0,0,0,0.5); }
.size-chart-modal__inner { padding: 1.5rem; }
.size-chart-modal__header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; }
.size-chart-modal__header h3 { margin: 0; font-size: 1.1rem; }
.size-chart-modal__header button { background: none; border: none; font-size: 1.5rem; cursor: pointer; padding: 0; line-height: 1; }
.size-chart-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.size-chart-table th, .size-chart-table td { padding: 0.5rem 0.75rem; border: 1px solid #e5e5e5; text-align: center; }
.size-chart-table th { background: #f9f9f9; font-weight: 600; }
</style>
{%- endif -%}
Set up the JSON metafield in Shopify admin with this structure: {"headers": ["Size", "Chest", "Waist", "Length"], "rows": [["S", "36", "30", "28"], ["M", "38", "32", "29"]]}. Uses the native HTML <dialog> element — no JavaScript library needed.
5. Product Tabs
Replaces: Product tab apps ($5-15/month).
{% comment %} snippets/product-tabs.liquid {% endcomment %}
{%- assign has_specs = false -%}
{%- if product.metafields.custom.specifications != blank -%}{%- assign has_specs = true -%}{%- endif -%}
<div class="product-tabs">
<div class="product-tabs__nav" role="tablist">
<button class="product-tabs__btn is-active" data-tab="description" role="tab" aria-selected="true">Description</button>
{%- if has_specs -%}
<button class="product-tabs__btn" data-tab="specs" role="tab" aria-selected="false">Specifications</button>
{%- endif -%}
<button class="product-tabs__btn" data-tab="shipping" role="tab" aria-selected="false">Shipping</button>
</div>
<div class="product-tabs__panel is-active" data-panel="description" role="tabpanel">
{{ product.description }}
</div>
{%- if has_specs -%}
<div class="product-tabs__panel" data-panel="specs" role="tabpanel">
{{ product.metafields.custom.specifications | metafield_tag }}
</div>
{%- endif -%}
<div class="product-tabs__panel" data-panel="shipping" role="tabpanel">
<p>Free shipping on orders over $75. Standard delivery in 3-5 business days.</p>
<p>Free returns within 30 days of purchase.</p>
</div>
</div>
<script>
document.querySelectorAll('.product-tabs__btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var tab = this.dataset.tab;
this.closest('.product-tabs').querySelectorAll('.product-tabs__btn').forEach(function(b) {
b.classList.remove('is-active'); b.setAttribute('aria-selected', 'false');
});
this.closest('.product-tabs').querySelectorAll('.product-tabs__panel').forEach(function(p) {
p.classList.remove('is-active');
});
this.classList.add('is-active'); this.setAttribute('aria-selected', 'true');
this.closest('.product-tabs').querySelector('[data-panel="' + tab + '"]').classList.add('is-active');
});
});
</script>
<style>
.product-tabs__nav { display: flex; gap: 0; border-bottom: 2px solid #e5e5e5; margin-bottom: 1.5rem; }
.product-tabs__btn { background: none; border: none; padding: 0.75rem 1.25rem; font-size: 0.9rem; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; color: #666; }
.product-tabs__btn.is-active { color: #111; border-bottom-color: currentColor; }
.product-tabs__panel { display: none; }
.product-tabs__panel.is-active { display: block; }
</style>
Zero dependencies. Accessible with proper ARIA attributes. Vanilla JS event delegation keeps it under 500 bytes.
Conversion and Sales Snippets
6. Free Shipping Progress Bar
Replaces: Free shipping bar apps ($0-10/month).
{% comment %} snippets/free-shipping-bar.liquid {% endcomment %}
{% comment %} Usage: {% render 'free-shipping-bar' %} in cart template {% endcomment %}
{%- assign threshold_cents = 7500 -%}
{%- assign remaining = threshold_cents | minus: cart.total_price -%}
{%- assign progress = cart.total_price | times: 100 | divided_by: threshold_cents -%}
{%- if progress > 100 -%}{%- assign progress = 100 -%}{%- endif -%}
<div class="shipping-progress">
<div class="shipping-progress__bar">
<div class="shipping-progress__fill" style="width: {{ progress }}%"></div>
</div>
{%- if remaining > 0 -%}
<p class="shipping-progress__text">Add <strong>{{ remaining | money }}</strong> for free shipping</p>
{%- else -%}
<p class="shipping-progress__text shipping-progress__text--done">You qualify for free shipping!</p>
{%- endif -%}
</div>
<style>
.shipping-progress { padding: 0.75rem 0; }
.shipping-progress__bar { height: 6px; background: #e5e5e5; border-radius: 3px; overflow: hidden; }
.shipping-progress__fill { height: 100%; background: linear-gradient(90deg, #5C6AC4, #00A0AC); border-radius: 3px; transition: width 0.3s; }
.shipping-progress__text { font-size: 0.8rem; text-align: center; margin-top: 0.5rem; color: #666; }
.shipping-progress__text--done { color: #22c55e; font-weight: 600; }
</style>
This is one of the snippets I add to nearly every cart I build. Simple, effective, and directly tied to AOV growth strategies.
7. Stock Level Indicator
Replaces: Scarcity/urgency apps ($5-15/month).
{% comment %} snippets/stock-indicator.liquid {% endcomment %}
{% comment %} Usage: {% render 'stock-indicator', variant: product.selected_or_first_available_variant %} {% endcomment %}
{%- if variant.inventory_management == 'shopify' and variant.inventory_policy == 'deny' -%}
{%- if variant.inventory_quantity <= 0 -%}
<p class="stock-indicator stock-indicator--out">Sold out</p>
{%- elsif variant.inventory_quantity <= 5 -%}
<p class="stock-indicator stock-indicator--low">Only {{ variant.inventory_quantity }} left in stock</p>
{%- elsif variant.inventory_quantity <= 20 -%}
<p class="stock-indicator stock-indicator--ok">In stock — ships within 24 hours</p>
{%- else -%}
<p class="stock-indicator stock-indicator--ok">In stock</p>
{%- endif -%}
{%- endif -%}
<style>
.stock-indicator { font-size: 0.85rem; font-weight: 500; margin: 0.5rem 0; display: flex; align-items: center; gap: 0.4rem; }
.stock-indicator::before { content: ''; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.stock-indicator--ok::before { background: #22c55e; }
.stock-indicator--low::before { background: #f59e0b; }
.stock-indicator--out::before { background: #ef4444; }
</style>
Only shows urgency when inventory is genuinely low. Fake urgency erodes trust — honest stock indicators build it. This is a core principle in every CRO audit I run.
8. Recently Viewed Products
Replaces: Recently viewed apps ($5-15/month).
{% comment %} snippets/recently-viewed.liquid {% endcomment %}
<div class="recently-viewed" id="recently-viewed" style="display:none;">
<h3 class="recently-viewed__title">Recently Viewed</h3>
<div class="recently-viewed__grid" id="recently-viewed-grid"></div>
</div>
<script>
(function() {
var KEY = 'recently_viewed';
var MAX = 6;
var current = '{{ product.handle }}';
// Save current product
if (current) {
var items = JSON.parse(localStorage.getItem(KEY) || '[]');
items = items.filter(function(h) { return h !== current; });
items.unshift(current);
if (items.length > MAX) items = items.slice(0, MAX);
localStorage.setItem(KEY, JSON.stringify(items));
}
// Render recently viewed (exclude current)
var handles = JSON.parse(localStorage.getItem(KEY) || '[]').filter(function(h) { return h !== current; });
if (handles.length === 0) return;
var grid = document.getElementById('recently-viewed-grid');
var loaded = 0;
handles.slice(0, 4).forEach(function(handle) {
fetch('/products/' + handle + '.js')
.then(function(r) { return r.json(); })
.then(function(p) {
var card = document.createElement('a');
card.href = '/products/' + p.handle;
card.className = 'recently-viewed__card';
card.innerHTML = '<img src="' + p.featured_image.replace('.jpg', '_300x.jpg').replace('.png', '_300x.png') + '" alt="' + p.title + '" loading="lazy" width="150" height="150">'
+ '<span class="recently-viewed__name">' + p.title + '</span>'
+ '<span class="recently-viewed__price">' + (p.price / 100).toLocaleString('en-US', {style: 'currency', currency: 'USD'}) + '</span>';
grid.appendChild(card);
loaded++;
if (loaded > 0) document.getElementById('recently-viewed').style.display = '';
})
.catch(function() {});
});
})();
</script>
<style>
.recently-viewed { margin: 2rem 0; padding-top: 2rem; border-top: 1px solid #e5e5e5; }
.recently-viewed__title { font-size: 1.1rem; font-weight: 700; margin-bottom: 1rem; }
.recently-viewed__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.recently-viewed__card { text-decoration: none; color: inherit; }
.recently-viewed__card img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 8px; }
.recently-viewed__name { display: block; font-size: 0.8rem; font-weight: 500; margin-top: 0.5rem; line-height: 1.3; }
.recently-viewed__price { font-size: 0.8rem; color: #666; }
@media (max-width: 768px) { .recently-viewed__grid { grid-template-columns: repeat(2, 1fr); } }
</style>
Uses localStorage to persist across page views and the Shopify Product JSON endpoint to fetch display data. No app script on every page — this only runs on the product template.
9. Complementary Products (Cross-Sell)
Replaces: Cross-sell/upsell apps ($10-30/month).
{% comment %} snippets/product-recommendations.liquid {% endcomment %}
<div class="recommendations" id="product-recommendations" data-url="{{ routes.product_recommendations_url }}?section_id=product-recommendations&product_id={{ product.id }}&limit=4">
</div>
<script>
(function() {
var el = document.getElementById('product-recommendations');
if (!el) return;
fetch(el.dataset.url)
.then(function(r) { return r.text(); })
.then(function(html) {
var temp = document.createElement('div');
temp.innerHTML = html;
var inner = temp.querySelector('.recommendations__inner');
if (inner && inner.children.length > 0) {
el.innerHTML = inner.outerHTML;
}
});
})();
</script>
{% comment %} This section renders server-side when fetched via the recommendations API {% endcomment %}
<div class="recommendations__inner">
{%- if recommendations.performed and recommendations.products.size > 0 -%}
<h3>You May Also Like</h3>
<div class="recommendations__grid">
{%- for product in recommendations.products -%}
<a href="{{ product.url }}" class="recommendations__card">
{{ product.featured_image | image_url: width: 300 | image_tag: loading: 'lazy', alt: product.title }}
<span class="recommendations__name">{{ product.title }}</span>
<span class="recommendations__price">{{ product.price | money }}</span>
</a>
{%- endfor -%}
</div>
{%- endif -%}
</div>
<style>
.recommendations__inner h3 { font-size: 1.1rem; font-weight: 700; margin-bottom: 1rem; }
.recommendations__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; }
.recommendations__card { text-decoration: none; color: inherit; }
.recommendations__card img { width: 100%; border-radius: 8px; }
.recommendations__name { display: block; font-size: 0.85rem; font-weight: 500; margin-top: 0.5rem; }
.recommendations__price { font-size: 0.85rem; color: #666; }
@media (max-width: 768px) { .recommendations__grid { grid-template-columns: repeat(2, 1fr); } }
</style>
Uses Shopify’s built-in Product Recommendations API — the same AI-powered engine that apps use, but without the app fee or JavaScript overhead.
10. Cart Upsell Block
Replaces: Cart upsell apps ($15-30/month).
{% comment %} snippets/cart-upsell.liquid {% endcomment %}
{% comment %} Shows a complementary product in the cart based on what's already there {% endcomment %}
{%- assign upsell_product = nil -%}
{%- assign cart_tags = '' -%}
{%- for item in cart.items -%}
{%- for tag in item.product.tags -%}
{%- if tag contains 'upsell:' -%}
{%- assign upsell_handle = tag | remove: 'upsell:' -%}
{%- assign already_in_cart = false -%}
{%- for cart_item in cart.items -%}
{%- if cart_item.product.handle == upsell_handle -%}
{%- assign already_in_cart = true -%}
{%- endif -%}
{%- endfor -%}
{%- unless already_in_cart -%}
{%- assign upsell_product = all_products[upsell_handle] -%}
{%- endunless -%}
{%- endif -%}
{%- endfor -%}
{%- endfor -%}
{%- if upsell_product and upsell_product.available -%}
<div class="cart-upsell">
<p class="cart-upsell__label">Frequently bought together</p>
<div class="cart-upsell__product">
<a href="{{ upsell_product.url }}">
{{ upsell_product.featured_image | image_url: width: 80 | image_tag: loading: 'lazy', alt: upsell_product.title }}
</a>
<div class="cart-upsell__info">
<a href="{{ upsell_product.url }}" class="cart-upsell__name">{{ upsell_product.title }}</a>
<span class="cart-upsell__price">{{ upsell_product.price | money }}</span>
</div>
<button class="cart-upsell__add btn btn-sm" onclick="
fetch('/cart/add.js', {method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({id: {{ upsell_product.selected_or_first_available_variant.id }}, quantity: 1})})
.then(function() { window.location.reload(); });
">Add</button>
</div>
</div>
{%- endif -%}
<style>
.cart-upsell { padding: 1rem; background: #f9f9f9; border-radius: 8px; margin-top: 1rem; }
.cart-upsell__label { font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: #666; margin-bottom: 0.75rem; }
.cart-upsell__product { display: flex; align-items: center; gap: 0.75rem; }
.cart-upsell__product img { width: 60px; height: 60px; object-fit: cover; border-radius: 6px; }
.cart-upsell__info { flex: 1; }
.cart-upsell__name { font-size: 0.85rem; font-weight: 500; text-decoration: none; color: inherit; display: block; }
.cart-upsell__price { font-size: 0.8rem; color: #666; }
.cart-upsell__add { padding: 0.4rem 1rem; font-size: 0.8rem; }
</style>
Tag your products with upsell:product-handle to control which product appears as the upsell. The snippet checks the cart, finds tagged upsells, and skips any already in the cart. This approach powers the upsell system I built for Factory Direct Blinds.
Performance and Technical Snippets
11. Lazy Loading Images (Proper Implementation)
Replaces: Image optimizer apps ($5-20/month).
{% comment %} snippets/responsive-image.liquid {% endcomment %}
{% comment %} Usage: {% render 'responsive-image', image: product.featured_image, alt: product.title, eager: false %} {% endcomment %}
{%- if image -%}
{{ image | image_url: width: 800 | image_tag:
loading: eager | default: 'lazy',
widths: '200,400,600,800,1000',
sizes: '(max-width: 768px) 100vw, 50vw',
alt: alt | default: '',
class: 'responsive-img'
}}
{%- endif -%}
<style>
.responsive-img { width: 100%; height: auto; display: block; }
</style>
Shopify’s image_tag filter generates a proper srcset with multiple resolutions. The browser downloads only the size it needs. This replaces any image optimization app that lazy-loads or resizes images.
12. Critical CSS Inline Loading
Replaces: Speed optimization apps ($10-30/month).
{% comment %} Add to theme.liquid or layout/theme.liquid <head> section {% endcomment %}
{%- if template contains 'index' -%}
<style>
{% comment %} Inline critical above-the-fold CSS for homepage {% endcomment %}
.hero { position: relative; min-height: 80vh; display: flex; align-items: center; justify-content: center; }
.hero h1 { font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; line-height: 1.1; }
.hero .btn { padding: 1rem 2rem; font-size: 1.1rem; font-weight: 600; border-radius: 12px; }
</style>
{%- endif -%}
{% comment %} Defer non-critical CSS {% endcomment %}
<link rel="stylesheet" href="{{ 'theme.css' | asset_url }}" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="{{ 'theme.css' | asset_url }}"></noscript>
The media="print" onload="this.media='all'" pattern defers CSS without blocking rendering. Critical styles are inlined so the page renders immediately. This pattern contributed to the PageSpeed jump from 38 to 81 on Factory Direct Blinds.
13. Product Schema (JSON-LD)
Replaces: SEO schema apps ($5-15/month).
{% comment %} snippets/product-schema.liquid {% endcomment %}
{% comment %} Include in product template: {% render 'product-schema', product: product %} {% endcomment %}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Product",
"name": {{ product.title | json }},
"description": {{ product.description | strip_html | truncate: 500 | json }},
"url": "{{ shop.url }}{{ product.url }}",
"image": [
{%- for image in product.images limit: 5 -%}
"{{ image | image_url: width: 1200 }}"{% unless forloop.last %},{% endunless %}
{%- endfor -%}
],
"brand": {
"@type": "Brand",
"name": {{ product.vendor | json }}
},
"sku": {{ product.selected_or_first_available_variant.sku | json }},
"offers": {
"@type": "AggregateOffer",
"priceCurrency": "{{ shop.currency }}",
"lowPrice": {{ product.price_min | divided_by: 100.0 }},
"highPrice": {{ product.price_max | divided_by: 100.0 }},
"offerCount": {{ product.variants.size }},
"availability": "https://schema.org/{% if product.available %}InStock{% else %}OutOfStock{% endif %}",
"url": "{{ shop.url }}{{ product.url }}"
}
{%- if product.metafields.reviews.rating.value -%}
,"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": {{ product.metafields.reviews.rating.value.rating }},
"reviewCount": {{ product.metafields.reviews.rating_count }}
}
{%- endif -%}
}
</script>
Generates complete Product schema with images, brand, SKU, price range, availability, and review data. This is what Google needs for rich product results in search.
Content and Marketing Snippets
14. Blog Table of Contents
Replaces: TOC apps and plugins.
{% comment %} snippets/table-of-contents.liquid {% endcomment %}
{% comment %} Usage: {% render 'table-of-contents', content: article.content %} {% endcomment %}
{%- assign headings = content | split: '<h2' -%}
{%- if headings.size > 2 -%}
<nav class="toc" aria-label="Table of contents">
<p class="toc__title">In this article</p>
<ol class="toc__list">
{%- for block in headings -%}
{%- if forloop.first -%}{%- continue -%}{%- endif -%}
{%- assign heading_text = block | split: '>' | last | split: '</h2>' | first | strip_html | strip -%}
{%- assign heading_id = block | split: 'id="' -%}
{%- if heading_id.size > 1 -%}
{%- assign heading_id = heading_id[1] | split: '"' | first -%}
{%- else -%}
{%- assign heading_id = heading_text | handleize -%}
{%- endif -%}
{%- if heading_text != blank -%}
<li><a href="#{{ heading_id }}">{{ heading_text }}</a></li>
{%- endif -%}
{%- endfor -%}
</ol>
</nav>
{%- endif -%}
<style>
.toc { padding: 1.25rem 1.5rem; background: #f8f8f8; border-radius: 8px; margin-bottom: 2rem; border-left: 3px solid #5C6AC4; }
.toc__title { font-weight: 700; font-size: 0.9rem; margin-bottom: 0.75rem; }
.toc__list { padding-left: 1.25rem; margin: 0; }
.toc__list li { margin-bottom: 0.35rem; }
.toc__list a { font-size: 0.85rem; color: #5C6AC4; text-decoration: none; }
.toc__list a:hover { text-decoration: underline; }
</style>
Parses H2 headings from the article content and generates an anchor-linked table of contents automatically. Works with Hugo’s auto-generated heading IDs.
15. Custom Contact Form
Replaces: Form builder apps ($5-20/month).
{% comment %} sections/custom-contact-form.liquid {% endcomment %}
<div class="custom-form">
<h2>{{ section.settings.heading }}</h2>
{%- if section.settings.description != blank -%}
<p class="custom-form__desc">{{ section.settings.description }}</p>
{%- endif -%}
{% form 'contact', class: 'custom-form__form' %}
{%- if form.posted_successfully? -%}
<div class="custom-form__success">
<p>Thanks for reaching out. We will get back to you within 24 hours.</p>
</div>
{%- endif -%}
{%- if form.errors -%}
<div class="custom-form__errors">
{{ form.errors | default_errors }}
</div>
{%- endif -%}
<div class="custom-form__row">
<div class="custom-form__field">
<label for="contact-name">Name</label>
<input type="text" id="contact-name" name="contact[name]" placeholder="Your name" required>
</div>
<div class="custom-form__field">
<label for="contact-email">Email</label>
<input type="email" id="contact-email" name="contact[email]" placeholder="[email protected]" required>
</div>
</div>
{%- for block in section.blocks -%}
<div class="custom-form__field" {{ block.shopify_attributes }}>
<label for="contact-{{ block.id }}">{{ block.settings.label }}</label>
{%- if block.type == 'textarea' -%}
<textarea id="contact-{{ block.id }}" name="contact[{{ block.settings.label }}]" rows="4" placeholder="{{ block.settings.placeholder }}"></textarea>
{%- elsif block.type == 'select' -%}
<select id="contact-{{ block.id }}" name="contact[{{ block.settings.label }}]">
{%- assign options = block.settings.options | split: ',' -%}
<option value="">Select...</option>
{%- for opt in options -%}
<option value="{{ opt | strip }}">{{ opt | strip }}</option>
{%- endfor -%}
</select>
{%- else -%}
<input type="text" id="contact-{{ block.id }}" name="contact[{{ block.settings.label }}]" placeholder="{{ block.settings.placeholder }}">
{%- endif -%}
</div>
{%- endfor -%}
<button type="submit" class="btn btn-primary">{{ section.settings.button_text }}</button>
{% endform %}
</div>
{% schema %}
{
"name": "Custom Contact Form",
"settings": [
{ "type": "text", "id": "heading", "label": "Heading", "default": "Get in Touch" },
{ "type": "textarea", "id": "description", "label": "Description" },
{ "type": "text", "id": "button_text", "label": "Button text", "default": "Send Message" }
],
"blocks": [
{
"type": "text_field",
"name": "Text Field",
"settings": [
{ "type": "text", "id": "label", "label": "Label" },
{ "type": "text", "id": "placeholder", "label": "Placeholder" }
]
},
{
"type": "textarea",
"name": "Text Area",
"settings": [
{ "type": "text", "id": "label", "label": "Label" },
{ "type": "text", "id": "placeholder", "label": "Placeholder" }
]
},
{
"type": "select",
"name": "Dropdown",
"settings": [
{ "type": "text", "id": "label", "label": "Label" },
{ "type": "text", "id": "options", "label": "Options (comma-separated)" }
]
}
],
"presets": [{ "name": "Custom Contact Form" }]
}
{% endschema %}
Merchants can add custom fields through the theme editor using blocks — text fields, textareas, and dropdowns. Submissions go to Shopify’s built-in contact form system (visible in Settings > Notifications) with no third-party service required.
How to Install These Snippets
Step 1: Back up first. Duplicate your live theme before editing. Never edit a published theme directly.
Step 2: Choose the right location.
- Snippets (files in
snippets/directory) are reusable components you call with{% render 'snippet-name' %}. Use these for trust badges, stock indicators, recently viewed, schemas, and other elements you embed inside existing templates. - Sections (files in
sections/directory) are standalone page components with their own schema. Use these for announcement bars, contact forms, and any element merchants should be able to add, remove, or configure from the theme editor.
Step 3: Add the code. Create a new file in the appropriate directory, paste the snippet, and save.
Step 4: Include it. For snippets, add {% render 'snippet-name' %} in the template where you want it to appear. For sections, they become available in the theme editor automatically via their preset.
Step 5: Test. Preview on a development theme across desktop, tablet, and mobile. Check the browser console for JavaScript errors. Run PageSpeed Insights to confirm the speed improvement.
For a full walkthrough of Liquid architecture patterns, read my Shopify Liquid development guide.
Want Me to Audit Your App Stack and Build Custom Replacements?
I typically find $200-500/month in app costs that can be eliminated with custom Liquid on every store I audit. The replacement code loads faster, costs nothing to maintain, and gives you full control.
View my services or book a free strategy call — I’ll look at your installed apps live and tell you which ones can go.