Files
gh-sarojpunde-shopify-dev-t…/skills/shopify-snippet-library/SKILL.md
2025-11-30 08:54:05 +08:00

12 KiB

name, description
name description
Shopify Snippet Library Reusable Liquid snippet patterns with proper documentation and parameter handling

Shopify Snippet Library

Snippet Documentation Format

All snippets should include documentation using Liquid comments:

{% comment %}
  Snippet: [Name]
  Description: [What this snippet does]

  Parameters:
  - param_name {type} - Description [required/optional]

  Usage:
  {% render 'snippet-name', param_name: value %}

  Example:
  {% render 'product-card', product: product, show_vendor: true %}
{% endcomment %}

Common Snippet Patterns

1. Product Card

{% comment %}
  Snippet: Product Card
  Description: Displays a product with image, title, vendor, and price

  Parameters:
  - product {product} - The product object [required]
  - show_vendor {boolean} - Show product vendor (default: false) [optional]
  - image_size {number} - Image width in pixels (default: 400) [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'product-card', product: product, show_vendor: true, image_size: 600 %}
{% endcomment %}

{%- liquid
  assign show_vendor = show_vendor | default: false
  assign image_size = image_size | default: 400
-%}

{%- if product == blank -%}
  <div class="product-card product-card--empty {{ class }}">
    <p>Product not available</p>
  </div>
{%- else -%}
  <article class="product-card {{ class }}">
    <a href="{{ product.url }}" class="product-card__link">
      {%- if product.featured_image -%}
        <div class="product-card__image">
          <img
            src="{{ product.featured_image | image_url: width: image_size }}"
            alt="{{ product.featured_image.alt | escape }}"
            loading="lazy"
            width="{{ image_size }}"
            height="{{ image_size | divided_by: product.featured_image.aspect_ratio | ceil }}"
          >
        </div>
      {%- endif -%}

      <div class="product-card__info">
        {%- if show_vendor and product.vendor != blank -%}
          <p class="product-card__vendor">{{ product.vendor | escape }}</p>
        {%- endif -%}

        <h3 class="product-card__title">{{ product.title | escape }}</h3>

        <div class="product-card__price">
          {%- if product.compare_at_price > product.price -%}
            <span class="product-card__price--sale">{{ product.price | money }}</span>
            <span class="product-card__price--compare">{{ product.compare_at_price | money }}</span>
          {%- else -%}
            <span>{{ product.price | money }}</span>
          {%- endif -%}
        </div>
      </div>
    </a>
  </article>
{%- endif -%}
{% comment %}
  Snippet: Button
  Description: Renders a customizable button or link

  Parameters:
  - text {string} - Button text [required]
  - url {string} - Button URL (makes it a link) [optional]
  - style {string} - Button style: 'primary', 'secondary', 'outline' (default: 'primary') [optional]
  - size {string} - Button size: 'small', 'medium', 'large' (default: 'medium') [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'button', text: 'Add to Cart', style: 'primary', size: 'large' %}
  {% render 'button', text: 'Learn More', url: '/pages/about', style: 'outline' %}
{% endcomment %}

{%- liquid
  assign style = style | default: 'primary'
  assign size = size | default: 'medium'
  assign btn_class = 'btn btn--' | append: style | append: ' btn--' | append: size
  if class
    assign btn_class = btn_class | append: ' ' | append: class
  endif
-%}

{%- if url != blank -%}
  <a href="{{ url }}" class="{{ btn_class }}">
    {{ text | escape }}
  </a>
{%- else -%}
  <button type="button" class="{{ btn_class }}">
    {{ text | escape }}
  </button>
{%- endif -%}

3. Icon (SVG)

{% comment %}
  Snippet: Icon
  Description: Renders an SVG icon

  Parameters:
  - name {string} - Icon name (e.g., 'cart', 'heart', 'search') [required]
  - size {number} - Icon size in pixels (default: 24) [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'icon', name: 'cart', size: 20, class: 'icon-primary' %}
{% endcomment %}

{%- liquid
  assign size = size | default: 24
  assign icon_class = 'icon icon-' | append: name
  if class
    assign icon_class = icon_class | append: ' ' | append: class
  endif
-%}

<svg class="{{ icon_class }}" width="{{ size }}" height="{{ size }}" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
  {%- case name -%}
    {%- when 'cart' -%}
      <path d="M9 2L8 4H4C2.9 4 2 4.9 2 6V18C2 19.1 2.9 20 4 20H20C21.1 20 22 19.1 22 18V6C22 4.9 21.1 4 20 4H16L15 2H9Z" stroke="currentColor" stroke-width="2"/>
    {%- when 'heart' -%}
      <path d="M20.84 4.61C19.91 3.68 18.69 3.17 17.42 3.17C16.15 3.17 14.93 3.68 14 4.61L12 6.61L10 4.61C9.07 3.68 7.85 3.17 6.58 3.17C5.31 3.17 4.09 3.68 3.16 4.61C1.22 6.55 1.22 9.69 3.16 11.63L12 20.47L20.84 11.63C22.78 9.69 22.78 6.55 20.84 4.61Z" stroke="currentColor" stroke-width="2"/>
    {%- when 'search' -%}
      <circle cx="11" cy="11" r="8" stroke="currentColor" stroke-width="2"/>
      <path d="M21 21L16.65 16.65" stroke="currentColor" stroke-width="2"/>
    {%- when 'close' -%}
      <path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2"/>
    {%- else -%}
      <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
  {%- endcase -%}
</svg>

4. Form Input

{% comment %}
  Snippet: Form Input
  Description: Renders a form input field with label

  Parameters:
  - type {string} - Input type (text, email, tel, number, etc.) [required]
  - name {string} - Input name attribute [required]
  - label {string} - Input label [required]
  - required {boolean} - Make field required (default: false) [optional]
  - placeholder {string} - Placeholder text [optional]
  - value {string} - Default value [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'form-input', type: 'email', name: 'email', label: 'Email Address', required: true %}
{% endcomment %}

{%- liquid
  assign required = required | default: false
  assign input_id = 'input-' | append: name
-%}

<div class="form-field {{ class }}">
  <label for="{{ input_id }}" class="form-field__label">
    {{ label | escape }}
    {%- if required -%}
      <span class="form-field__required" aria-label="required">*</span>
    {%- endif -%}
  </label>

  <input
    type="{{ type }}"
    id="{{ input_id }}"
    name="{{ name }}"
    class="form-field__input"
    {%- if placeholder -%}placeholder="{{ placeholder | escape }}"{%- endif -%}
    {%- if value -%}value="{{ value | escape }}"{%- endif -%}
    {%- if required -%}required{%- endif -%}
    {%- if type == 'email' -%}autocomplete="email"{%- endif -%}
  >
</div>

5. Image with Fallback

{% comment %}
  Snippet: Responsive Image
  Description: Renders a responsive image with fallback

  Parameters:
  - image {image} - The image object [required]
  - width {number} - Image width (default: 800) [optional]
  - height {number} - Image height [optional]
  - alt {string} - Alt text (uses image.alt if not provided) [optional]
  - class {string} - Additional CSS classes [optional]
  - loading {string} - Loading attribute: 'lazy' or 'eager' (default: 'lazy') [optional]

  Usage:
  {% render 'image', image: product.featured_image, width: 600, alt: product.title %}
{% endcomment %}

{%- liquid
  assign width = width | default: 800
  assign loading = loading | default: 'lazy'
  assign alt_text = alt | default: image.alt
-%}

{%- if image != blank -%}
  {%- if height -%}
    <img
      src="{{ image | image_url: width: width, height: height }}"
      alt="{{ alt_text | escape }}"
      width="{{ width }}"
      height="{{ height }}"
      loading="{{ loading }}"
      class="{{ class }}"
    >
  {%- else -%}
    <img
      srcset="
        {{ image | image_url: width: 400 }} 400w,
        {{ image | image_url: width: 800 }} 800w,
        {{ image | image_url: width: 1200 }} 1200w
      "
      sizes="(min-width: 1024px) 33vw, (min-width: 768px) 50vw, 100vw"
      src="{{ image | image_url: width: width }}"
      alt="{{ alt_text | escape }}"
      width="{{ width }}"
      height="{{ width | divided_by: image.aspect_ratio | ceil }}"
      loading="{{ loading }}"
      class="{{ class }}"
    >
  {%- endif -%}
{%- else -%}
  <div class="image-placeholder {{ class }}" role="img" aria-label="No image available"></div>
{%- endif -%}

6. Price Display

{% comment %}
  Snippet: Price
  Description: Displays product price with sale indication

  Parameters:
  - product {product} - The product object [required]
  - show_compare {boolean} - Show compare at price (default: true) [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'price', product: product %}
  {% render 'price', product: product, show_compare: false %}
{% endcomment %}

{%- liquid
  assign show_compare = show_compare | default: true
  assign on_sale = false
  if product.compare_at_price > product.price
    assign on_sale = true
  endif
-%}

<div class="price {{ class }}{% if on_sale %} price--on-sale{% endif %}">
  {%- if on_sale -%}
    <span class="price__sale">{{ product.price | money }}</span>
    {%- if show_compare -%}
      <span class="price__compare">{{ product.compare_at_price | money }}</span>
    {%- endif -%}
  {%- else -%}
    <span class="price__regular">{{ product.price | money }}</span>
  {%- endif -%}
</div>

7. Badge / Tag

{% comment %}
  Snippet: Badge
  Description: Displays a badge or tag

  Parameters:
  - text {string} - Badge text [required]
  - style {string} - Badge style: 'sale', 'new', 'featured', 'default' (default: 'default') [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'badge', text: 'Sale', style: 'sale' %}
  {% render 'badge', text: 'New Arrival', style: 'new' %}
{% endcomment %}

{%- liquid
  assign style = style | default: 'default'
  assign badge_class = 'badge badge--' | append: style
  if class
    assign badge_class = badge_class | append: ' ' | append: class
  endif
-%}

{%- if text != blank -%}
  <span class="{{ badge_class }}">
    {{ text | escape }}
  </span>
{%- endif -%}

8. Loading Spinner

{% comment %}
  Snippet: Loading Spinner
  Description: Displays a loading spinner

  Parameters:
  - size {string} - Spinner size: 'small', 'medium', 'large' (default: 'medium') [optional]
  - class {string} - Additional CSS classes [optional]

  Usage:
  {% render 'loading-spinner', size: 'large' %}
{% endcomment %}

{%- liquid
  assign size = size | default: 'medium'
  assign spinner_class = 'spinner spinner--' | append: size
  if class
    assign spinner_class = spinner_class | append: ' ' | append: class
  endif
-%}

<div class="{{ spinner_class }}" role="status" aria-label="Loading">
  <svg class="spinner__svg" viewBox="0 0 50 50">
    <circle class="spinner__circle" cx="25" cy="25" r="20" fill="none" stroke-width="5"></circle>
  </svg>
  <span class="sr-only">Loading...</span>
</div>

Best Practices

1. Always Document Parameters

{% comment %}
  Parameters:
  - param {type} - Description [required/optional]
{% endcomment %}

2. Provide Defaults

{%- liquid
  assign show_vendor = show_vendor | default: false
  assign image_size = image_size | default: 400
-%}

3. Validate Required Parameters

{%- if product == blank -%}
  <p class="error">Product parameter is required</p>
  {%- return -%}
{%- endif -%}

4. Handle Empty States

{%- if image != blank -%}
  <!-- Image markup -->
{%- else -%}
  <div class="placeholder">No image available</div>
{%- endif -%}

5. Escape User-Provided Content

<h3>{{ product.title | escape }}</h3>
<p>{{ customer.name | escape }}</p>

6. Use Semantic HTML

<article>  {%- # For products -%}
<nav>      {%- # For navigation -%}
<aside>    {%- # For sidebars -%}
<section>  {%- # For content sections -%}

7. Include Accessibility Attributes

<button aria-label="Add {{ product.title | escape }} to cart">
  Add to Cart
</button>

<img src="..." alt="{{ image.alt | escape }}">

<div role="status" aria-live="polite">
  Item added to cart
</div>

Create well-documented, reusable snippets that are easy to understand and maintain.