Skip to main content

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>
{% 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

  1. Backward Compatible Changes: Add optional parameters
  2. 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

  1. Limit Nested Renders: Avoid deep nesting of snippets
  2. Cache Results: Use Liquid caching where possible
  3. Minimize Logic: Keep snippets simple and focused
  4. Optimize Images: Use appropriate image sizes in snippets
  5. Pre-compute Values: Calculate values before rendering
  6. Conditional Rendering: Only render when needed
  7. Reuse Snippets: Don't duplicate code, reuse snippets

Next Steps