Snippets
Snippets are reusable Liquid components that can be included in templates, sections, and other snippets. They help maintain consistency and reduce code duplication.
Snippet Overview
Snippets are stored in the snippets/ directory and can be rendered anywhere in your theme using the render tag.
Creating Snippets
Basic Snippet
Create a file in snippets/ directory:
{% comment %}
Snippet: product-card
Displays a product card
{% endcomment %}
<div class="product-card">
<a href="{{ product | product_url }}">
<img src="{{ product.featured_image | img_url: 'medium' }}" alt="{{ product.name }}">
<h3>{{ product.name }}</h3>
<p class="price">{{ product.price | money }}</p>
</a>
</div>
Using Snippets
Render snippets using the render tag:
{% render 'product-card', product: product %}
Snippet Parameters
Snippets can accept parameters:
{% comment %}
Snippet: button
Parameters:
- text: Button text
- url: Button URL
- style: Button style (primary, secondary)
{% endcomment %}
<a href="{{ url }}" class="btn btn-{{ style | default: 'primary' }}">
{{ text }}
</a>
Usage:
{% render 'button', text: 'Add to Cart', url: '/cart/add', style: 'primary' %}
Common Snippets
Product Card
{% comment %}
Snippet: product-card
{% endcomment %}
<div class="product-card" data-product-id="{{ product.id }}">
<a href="{{ product | product_url }}" class="product-link">
<div class="product-image">
<img
src="{{ product.featured_image | img_url: 'large' }}"
alt="{{ product.name }}"
loading="lazy"
>
{% if product.compare_at_price > product.price %}
<span class="badge sale-badge">Sale</span>
{% endif %}
</div>
<div class="product-info">
<h3 class="product-title">{{ product.name }}</h3>
<div class="product-price">
<span class="price">{{ product.price | money }}</span>
{% if product.compare_at_price > product.price %}
<span class="compare-price">{{ product.compare_at_price | money }}</span>
{% endif %}
</div>
{% if product.available %}
<button class="btn-add-to-cart" data-product-id="{{ product.id }}">
Add to Cart
</button>
{% else %}
<span class="out-of-stock">Out of Stock</span>
{% endif %}
</div>
</a>
</div>
Breadcrumbs
{% comment %}
Snippet: breadcrumbs
{% endcomment %}
<nav class="breadcrumbs" aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
{% if collection %}
<li><a href="/collections">{{ collection.name }}</a></li>
{% endif %}
{% if product %}
<li><a href="{{ collection | collection_url }}">{{ collection.name }}</a></li>
<li aria-current="page">{{ product.name }}</li>
{% elsif page %}
<li aria-current="page">{{ page.title }}</li>
{% endif %}
</ol>
</nav>
Pagination
{% comment %}
Snippet: pagination
Parameters:
- paginate: Pagination object
{% endcomment %}
{% if paginate.pages > 1 %}
<nav class="pagination" aria-label="Pagination">
<ul>
{% if paginate.previous %}
<li>
<a href="{{ paginate.previous.url }}" aria-label="Previous page">
← Previous
</a>
</li>
{% endif %}
{% for part in paginate.parts %}
{% if part.is_link %}
<li>
<a href="{{ part.url }}">{{ part.title }}</a>
</li>
{% else %}
<li class="current" aria-current="page">
<span>{{ part.title }}</span>
</li>
{% endif %}
{% endfor %}
{% if paginate.next %}
<li>
<a href="{{ paginate.next.url }}" aria-label="Next page">
Next →
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
Icon
{% comment %}
Snippet: icon
Parameters:
- name: Icon name
- size: Icon size (small, medium, large)
{% endcomment %}
<svg class="icon icon-{{ name }} icon-{{ size | default: 'medium' }}" aria-hidden="true">
<use href="#icon-{{ name }}"></use>
</svg>
Usage:
{% render 'icon', name: 'cart', size: 'large' %}
Social Sharing
{% comment %}
Snippet: social-sharing
Parameters:
- url: URL to share
- title: Title to share
{% endcomment %}
<div class="social-sharing">
<span>Share:</span>
<a
href="https://www.facebook.com/sharer/sharer.php?u={{ url | url_encode }}"
target="_blank"
aria-label="Share on Facebook"
>
{% render 'icon', name: 'facebook' %}
</a>
<a
href="https://twitter.com/intent/tweet?url={{ url | url_encode }}&text={{ title | url_encode }}"
target="_blank"
aria-label="Share on Twitter"
>
{% render 'icon', name: 'twitter' %}
</a>
<a
href="https://www.linkedin.com/shareArticle?url={{ url | url_encode }}"
target="_blank"
aria-label="Share on LinkedIn"
>
{% render 'icon', name: 'linkedin' %}
</a>
</div>
Rating Stars
{% comment %}
Snippet: rating
Parameters:
- rating: Rating value (0-5)
{% endcomment %}
<div class="rating" data-rating="{{ rating }}">
{% assign full_stars = rating | floor %}
{% assign has_half = rating | modulo: 1 %}
{% for i in (1..5) %}
{% if i <= full_stars %}
<span class="star full">★</span>
{% elsif i == full_stars | plus: 1 and has_half > 0 %}
<span class="star half">★</span>
{% else %}
<span class="star empty">☆</span>
{% endif %}
{% endfor %}
<span class="rating-value">{{ rating }}</span>
</div>
Add to Cart Modal
{% comment %}
Snippet: add-to-cart-modal
{% endcomment %}
<div id="add-to-cart-modal" class="modal" aria-hidden="true">
<div class="modal-overlay" data-close-modal></div>
<div class="modal-content">
<button class="modal-close" aria-label="Close modal" data-close-modal>×</button>
<div class="modal-body">
<div class="success-icon">✓</div>
<h2>Item Added to Cart</h2>
<p class="product-name"></p>
<div class="modal-actions">
<a href="/cart" class="btn btn-primary">View Cart</a>
<button class="btn btn-secondary" data-close-modal>Continue Shopping</button>
</div>
</div>
</div>
</div>
Snippet Best Practices
1. Keep Snippets Focused
Each snippet should have a single responsibility:
{% comment %} Good: Focused snippet {% endcomment %}
{% render 'product-image', product: product %}
{% render 'product-info', product: product %}
2. Use Descriptive Names
Use clear, descriptive names:
- ✅
product-card.liquid - ✅
breadcrumbs.liquid - ✅
add-to-cart-button.liquid - ❌
card.liquid - ❌
nav.liquid
3. Document Parameters
Always document parameters in comments:
{% comment %}
Snippet: product-card
Parameters:
- product: Product object (required)
- show_vendor: Show vendor name (optional, default: false)
- image_size: Image size (optional, default: 'medium')
{% endcomment %}
4. Provide Default Values
Use the default filter for optional parameters:
{% assign image_size = image_size | default: 'medium' %}
{% assign show_vendor = show_vendor | default: false %}
5. Handle Missing Data
Always handle cases where data might be missing:
{% if product %}
{% render 'product-card', product: product %}
{% else %}
<p>Product not found</p>
{% endif %}
6. Reuse Snippets
Don't duplicate code - create reusable snippets:
{% comment %} Instead of duplicating, reuse {% endcomment %}
{% for product in products %}
{% render 'product-card', product: product %}
{% endfor %}
7. Organize by Function
Group related snippets:
- Product-related:
product-card.liquid,product-form.liquid - Navigation:
breadcrumbs.liquid,menu.liquid - UI components:
button.liquid,modal.liquid
Snippet Organization
Organize snippets logically:
snippets/
product/
product-card.liquid
product-form.liquid
product-gallery.liquid
navigation/
breadcrumbs.liquid
menu.liquid
pagination.liquid
ui/
button.liquid
modal.liquid
icon.liquid
cart/
cart-drawer.liquid
cart-item.liquid
Advanced Snippets
Conditional Rendering
{% comment %}
Snippet: conditional-content
{% endcomment %}
{% if condition %}
{% render 'content-a' %}
{% else %}
{% render 'content-b' %}
{% endif %}
Nested Snippets
Snippets can render other snippets:
{% comment %}
Snippet: product-grid
{% endcomment %}
<div class="product-grid">
{% for product in products %}
{% render 'product-card', product: product %}
{% endfor %}
</div>
Snippet with Settings
{% comment %}
Snippet: featured-section
Uses theme settings
{% endcomment %}
{% if settings.show_featured_section %}
<section class="featured-section">
<h2>{{ settings.featured_title }}</h2>
{% render 'product-grid', products: collections.featured.products %}
</section>
{% endif %}
Snippet Organization Patterns
Pattern 1: By Component Type
snippets/
products/
product-card.liquid
product-grid.liquid
product-list.liquid
navigation/
breadcrumbs.liquid
menu.liquid
pagination.liquid
forms/
search-form.liquid
newsletter-form.liquid
contact-form.liquid
Pattern 2: By Feature
snippets/
cart/
cart-item.liquid
cart-summary.liquid
cart-empty.liquid
checkout/
shipping-form.liquid
payment-form.liquid
order-summary.liquid
Pattern 3: Flat Structure (Small Themes)
snippets/
product-card.liquid
breadcrumbs.liquid
menu.liquid
pagination.liquid
Snippet Reusability Examples
Highly Reusable Button Snippet
{% comment %}
Snippet: button
Highly reusable button component
Parameters:
- text: Button text (required)
- url: Button URL (optional)
- style: Button style - primary, secondary, outline (default: primary)
- size: Button size - small, medium, large (default: medium)
- icon: Icon name (optional)
- disabled: Disable button (default: false)
- class: Additional CSS classes (optional)
{% endcomment %}
{% assign button_style = style | default: 'primary' %}
{% assign button_size = size | default: 'medium' %}
{% assign button_disabled = disabled | default: false %}
{% if url and button_disabled == false %}
<a href="{{ url }}"
class="btn btn-{{ button_style }} btn-{{ button_size }} {{ class }}">
{% if icon %}
<span class="icon icon-{{ icon }}"></span>
{% endif %}
{{ text }}
</a>
{% else %}
<button type="button"
class="btn btn-{{ button_style }} btn-{{ button_size }} {{ class }}"
{% if button_disabled %}disabled{% endif %}>
{% if icon %}
<span class="icon icon-{{ icon }}"></span>
{% endif %}
{{ text }}
</button>
{% endif %}
Usage Examples:
{% render 'button', text: 'Add to Cart', url: '/cart/add', style: 'primary' %}
{% render 'button', text: 'Learn More', style: 'outline', size: 'large' %}
{% render 'button', text: 'Submit', icon: 'check', disabled: true %}
Flexible Product Card Snippet
{% comment %}
Snippet: product-card
Flexible product card with multiple display options
Parameters:
- product: Product object (required)
- show_price: Show price (default: true)
- show_vendor: Show vendor (default: false)
- show_badge: Show sale badge (default: true)
- image_size: Image size - small, medium, large (default: medium)
- class: Additional CSS classes
{% endcomment %}
{% assign show_price = show_price | default: true %}
{% assign show_vendor = show_vendor | default: false %}
{% assign show_badge = show_badge | default: true %}
{% assign image_size = image_size | default: 'medium' %}
<div class="product-card {{ class }}" data-product-id="{{ product.id }}">
<a href="{{ product | product_url }}" class="product-link">
<div class="product-image">
<img src="{{ product.featured_image | img_url: image_size }}"
alt="{{ product.name | escape }}"
loading="lazy">
{% if show_badge and product.compare_at_price > product.price %}
<span class="badge sale-badge">Sale</span>
{% endif %}
</div>
<div class="product-info">
{% if show_vendor and product.vendor %}
<p class="product-vendor">{{ product.vendor }}</p>
{% endif %}
<h3 class="product-title">{{ product.name }}</h3>
{% if show_price %}
<div class="product-price">
<span class="price">{{ product.price | money }}</span>
{% if product.compare_at_price > product.price %}
<span class="compare-price">{{ product.compare_at_price | money }}</span>
{% endif %}
</div>
{% endif %}
</div>
</a>
</div>
Snippet Performance Considerations
1. Limit Nested Renders
❌ Avoid deep nesting:
{% for collection in collections %}
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% render 'product-badge', product: product %}
{% render 'product-price', product: product %}
{% endfor %}
{% endfor %}
✅ Combine into single snippet:
{% for collection in collections %}
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
{% endfor %}
2. Cache Expensive Operations
{% comment %} Cache product count {% endcomment %}
{% assign product_count = collection.products.size %}
{% assign has_discount = product.compare_at_price > product.price %}
3. Use Conditional Rendering
{% if product.available %}
{% render 'add-to-cart-button', product: product %}
{% else %}
{% render 'out-of-stock-message' %}
{% endif %}
4. Minimize Logic in Snippets
❌ Too much logic:
{% for i in (1..100) %}
{% if product.tags contains 'featured' %}
{% if product.price > 100 %}
<!-- Complex nested logic -->
{% endif %}
{% endif %}
{% endfor %}
✅ Pre-compute values:
{% assign is_featured = product.tags contains 'featured' %}
{% assign is_premium = product.price > 100 %}
{% if is_featured and is_premium %}
<!-- Simple condition -->
{% endif %}
Snippet Versioning Guide
Versioning Strategy
- Backward Compatible Changes: Add optional parameters
- Breaking Changes: Create new snippet version
Example: Versioned Snippet
{% comment %}
Snippet: product-card-v2
Version 2.0 - Added support for variants
Migration: Rename product-card to product-card-v1, use product-card-v2
{% endcomment %}
<div class="product-card-v2">
<!-- New version with variant support -->
</div>
Migration Pattern
{% comment %} Use new version if available, fallback to old {% endcomment %}
{% if snippet_exists.product-card-v2 %}
{% render 'product-card-v2', product: product %}
{% else %}
{% render 'product-card', product: product %}
{% endif %}
Snippet Testing Examples
Testing Snippet with Different Data
{% comment %} Test product card with various products {% endcomment %}
{% assign test_products = collections.all.products | limit: 3 %}
{% for product in test_products %}
<div class="test-case">
<h4>Test Case {{ forloop.index }}</h4>
{% render 'product-card', product: product %}
</div>
{% endfor %}
Testing Edge Cases
{% comment %} Test with missing data {% endcomment %}
{% render 'product-card', product: null %}
{% render 'product-card', product: empty_product %}
{% render 'product-card', product: product_without_image %}
Testing Snippet Parameters
{% comment %} Test all parameter combinations {% endcomment %}
{% render 'button', text: 'Test', style: 'primary' %}
{% render 'button', text: 'Test', style: 'secondary' %}
{% render 'button', text: 'Test', style: 'outline' %}
{% render 'button', text: 'Test', size: 'small' %}
{% render 'button', text: 'Test', size: 'large' %}
Performance Tips
- Limit Nested Renders: Avoid deep nesting of snippets
- Cache Results: Use Liquid caching where possible
- Minimize Logic: Keep snippets simple and focused
- Optimize Images: Use appropriate image sizes in snippets
- Pre-compute Values: Calculate values before rendering
- Conditional Rendering: Only render when needed
- Reuse Snippets: Don't duplicate code, reuse snippets
Next Steps
- Sections - Learn about page sections
- Assets - Manage theme assets
- Widgets - Use widgets with snippets
- Best Practices - Snippet best practices