shopify section patterns

Shopify Section Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "shopify section patterns" with this command: npx skills add sarojpunde/shopify-dev-toolkit-claude-plugins/sarojpunde-shopify-dev-toolkit-claude-plugins-shopify-section-patterns

Shopify Section Patterns

Section Anatomy

A complete Shopify section consists of:

  • Liquid markup - HTML structure with dynamic content

  • Inline CSS - {% stylesheet %} tag (optional)

  • Inline JavaScript - {% javascript %} tag (optional)

  • Schema - {% schema %} JSON configuration

Complete Section Template

{%- comment -%} Section: [Name] Description: [Brief description] Usage: Add via Theme Editor {%- endcomment -%}

{%- liquid assign heading = section.settings.heading | default: 'Default Heading' assign bg_color = section.settings.bg_color assign text_color = section.settings.text_color -%}

<section id="section-{{ section.id }}" class="my-section" data-section-id="{{ section.id }}"

<div class="container"> {%- if heading != blank -%} <h2>{{ heading | escape }}</h2> {%- endif -%}

{%- comment -%} Section content {%- endcomment -%}

</div> </section>

{% stylesheet %} #section-{{ section.id }} { padding: {{ section.settings.padding_top }}px 0 {{ section.settings.padding_bottom }}px; background-color: {{ bg_color }}; color: {{ text_color }}; }

.container { max-width: 1200px; margin: 0 auto; padding: 0 20px; }

@media (min-width: 768px) { /* Tablet styles */ }

@media (min-width: 1024px) { /* Desktop styles */ } {% endstylesheet %}

{% javascript %} (function() { 'use strict';

function initSection(sectionId) {
  const section = document.querySelector('[data-section-id="' + sectionId + '"]');
  if (!section) return;

  // Your JavaScript here
}

// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
  initSection('{{ section.id }}');
});

// Re-initialize when section reloads in theme editor
document.addEventListener('shopify:section:load', function(event) {
  if (event.detail.sectionId === '{{ section.id }}') {
    initSection('{{ section.id }}');
  }
});

})(); {% endjavascript %}

{% schema %} { "name": "Section Name", "tag": "section", "class": "section-wrapper", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Default Heading" }, { "type": "color", "id": "bg_color", "label": "Background Color", "default": "#ffffff" }, { "type": "color", "id": "text_color", "label": "Text Color", "default": "#000000" }, { "type": "range", "id": "padding_top", "label": "Top Spacing", "min": 0, "max": 100, "step": 4, "unit": "px", "default": 40 }, { "type": "range", "id": "padding_bottom", "label": "Bottom Spacing", "min": 0, "max": 100, "step": 4, "unit": "px", "default": 40 } ], "presets": [ { "name": "Section Name" } ] } {% endschema %}

When to Use Inline CSS/JS

Use Inline {% stylesheet %} When:

  • CSS needs Liquid variables: {{ section.settings.color }}

  • Dynamic styles based on merchant settings

  • Section-specific styles that don't need external file

Use Inline {% javascript %} When:

  • JS needs Liquid settings: {{ section.settings.enable_feature }}

  • Section-specific functionality

  • Need access to {{ section.id }} or other Liquid values

Skip Inline Tags When:

  • Styles/scripts are static and reusable

  • Better to use theme.css or theme.js

  • No Liquid variables needed

Common Section Patterns

  1. Product Grid Section

{%- liquid assign collection = section.settings.collection assign products_count = section.settings.products_count assign columns = section.settings.columns_desktop -%}

<div class="product-grid"> {%- for product in collection.products limit: products_count -%} <div class="product-item"> <a href="{{ product.url }}"> {%- if product.featured_image -%} <img src="{{ product.featured_image | image_url: width: 400 }}" alt="{{ product.featured_image.alt | escape }}" loading="lazy" > {%- endif -%}

    &#x3C;h3>{{ product.title | escape }}&#x3C;/h3>
    &#x3C;p>{{ product.price | money }}&#x3C;/p>
  &#x3C;/a>
&#x3C;/div>

{%- endfor -%} </div>

{% stylesheet %} .product-grid { display: grid; gap: 1.5rem; grid-template-columns: 1fr; }

@media (min-width: 768px) { .product-grid { grid-template-columns: repeat({{ columns }}, 1fr); } } {% endstylesheet %}

  1. Hero Banner Section

{%- liquid assign image = section.settings.image assign heading = section.settings.heading assign text = section.settings.text assign button_label = section.settings.button_label assign button_link = section.settings.button_link -%}

<div class="hero-banner"> {%- if image -%} <div class="hero-banner__image"> <img src="{{ image | image_url: width: 1600 }}" alt="{{ image.alt | escape }}" > </div> {%- endif -%}

<div class="hero-banner__content"> {%- if heading != blank -%} <h1>{{ heading | escape }}</h1> {%- endif -%}

{%- if text != blank -%}
  &#x3C;p>{{ text }}&#x3C;/p>
{%- endif -%}

{%- if button_label != blank and button_link != blank -%}
  &#x3C;a href="{{ button_link }}" class="button">
    {{ button_label | escape }}
  &#x3C;/a>
{%- endif -%}

</div> </div>

{% stylesheet %} .hero-banner { position: relative; min-height: 500px; display: flex; align-items: center; justify-content: center; text-align: center; }

.hero-banner__image { position: absolute; inset: 0; z-index: -1; }

.hero-banner__image img { width: 100%; height: 100%; object-fit: cover; }

.hero-banner__content { padding: 2rem; background: rgba(255, 255, 255, 0.9); border-radius: 8px; }

.button { display: inline-block; padding: 1rem 2rem; background: #000; color: #fff; text-decoration: none; border-radius: 4px; margin-top: 1rem; } {% endstylesheet %}

  1. Testimonials Section with Blocks

<div class="testimonials"> {%- for block in section.blocks -%} <div class="testimonial" {{ block.shopify_attributes }}> {%- if block.settings.quote != blank -%} <blockquote> {{ block.settings.quote }} </blockquote> {%- endif -%}

  {%- if block.settings.author != blank -%}
    &#x3C;cite>{{ block.settings.author | escape }}&#x3C;/cite>
  {%- endif -%}
&#x3C;/div>

{%- endfor -%} </div>

{% schema %} { "name": "Testimonials", "blocks": [ { "type": "testimonial", "name": "Testimonial", "settings": [ { "type": "textarea", "id": "quote", "label": "Quote" }, { "type": "text", "id": "author", "label": "Author" } ] } ], "presets": [ { "name": "Testimonials", "blocks": [ { "type": "testimonial" } ] } ] } {% endschema %}

Shopify Section Events

Handle theme editor events:

{% javascript %} (function() { 'use strict';

function initSection(sectionId) {
  const section = document.querySelector('[data-section-id="' + sectionId + '"]');
  if (!section) return;

  console.log('Section initialized:', sectionId);
}

function cleanupSection(sectionId) {
  // Clean up event listeners, timers, etc.
  console.log('Section cleaned up:', sectionId);
}

// Load event - section added or page loaded
document.addEventListener('shopify:section:load', function(event) {
  initSection(event.detail.sectionId);
});

// Unload event - section removed
document.addEventListener('shopify:section:unload', function(event) {
  cleanupSection(event.detail.sectionId);
});

// Select event - section selected in theme editor
document.addEventListener('shopify:section:select', function(event) {
  console.log('Section selected:', event.detail.sectionId);
});

// Deselect event - section deselected in theme editor
document.addEventListener('shopify:section:deselect', function(event) {
  console.log('Section deselected:', event.detail.sectionId);
});

// Block select event - block selected in theme editor
document.addEventListener('shopify:block:select', function(event) {
  console.log('Block selected:', event.detail.blockId);
});

// Block deselect event - block deselected in theme editor
document.addEventListener('shopify:block:deselect', function(event) {
  console.log('Block deselected:', event.detail.blockId);
});

// Initialize on page load
document.addEventListener('DOMContentLoaded', function() {
  initSection('{{ section.id }}');
});

})(); {% endjavascript %}

Best Practices

  1. Use Section ID for Unique Styling

<div id="section-{{ section.id }}" class="my-section"> <!-- Content --> </div>

{% stylesheet %} #section-{{ section.id }} { /* Section-specific styles using Liquid variables */ background: {{ section.settings.bg_color }}; }

.my-section { /* General styles without Liquid variables */ padding: 2rem 0; } {% endstylesheet %}

  1. Provide Sensible Defaults

{%- liquid assign heading = section.settings.heading | default: 'Default Heading' assign columns = section.settings.columns | default: 3 assign show_prices = section.settings.show_prices | default: true -%}

  1. Handle Empty States

{%- if collection.products.size > 0 -%} <!-- Show products --> {%- else -%} <p>No products available in this collection.</p> {%- endif -%}

  1. Mobile-First Responsive

/* Mobile first - base styles */ .grid { grid-template-columns: 1fr; }

/* Tablet and up */ @media (min-width: 768px) { .grid { grid-template-columns: repeat(2, 1fr); } }

/* Desktop and up */ @media (min-width: 1024px) { .grid { grid-template-columns: repeat(3, 1fr); } }

  1. Use data- Attributes for JavaScript

<div class="slider" data-autoplay="{{ section.settings.autoplay }}" data-speed="{{ section.settings.speed }}"

<!-- Slider content --> </div>

{% javascript %} const slider = document.querySelector('.slider'); const autoplay = slider.dataset.autoplay === 'true'; const speed = parseInt(slider.dataset.speed, 10); {% endjavascript %}

Common Patterns

Conditional Classes

<div class="card{% if product.available %} in-stock{% else %} sold-out{% endif %}"> <!-- Card content --> </div>

Dynamic Grid Columns

{% stylesheet %} .product-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat({{ section.settings.columns_mobile }}, 1fr); }

@media (min-width: 1024px) { .product-grid { grid-template-columns: repeat({{ section.settings.columns_desktop }}, 1fr); } } {% endstylesheet %}

Loading States

{% javascript %} function addToCart(button) { button.classList.add('loading'); button.disabled = true;

// Add to cart logic...

button.classList.remove('loading');
button.disabled = false;

} {% endjavascript %}

Create sections that are flexible, performant, and easy for merchants to customize through the theme editor.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

shopify-api-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

shopify workflow & tools

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

polaris-fundamentals

No summary provided by upstream source.

Repository SourceNeeds Review