원클릭으로
shopify-section-patterns
Best practices for creating Shopify 2.0 sections with inline CSS and JavaScript
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Best practices for creating Shopify 2.0 sections with inline CSS and JavaScript
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Prisma ORM best practices for Shopify apps including multi-tenant data isolation, query optimization, transaction patterns, and migration strategies. Auto-invoked when working with database operations.
Build consistent UI using Polaris Web Components patterns for common page layouts like index pages, detail pages, forms, and empty states. Use this skill when creating new pages or refactoring existing UI components.
Common Shopify Admin GraphQL API patterns for product queries, metafield operations, webhooks, and bulk operations. Auto-invoked when working with Shopify API integration.
Polaris composition patterns and page templates for common Shopify app layouts. Provides index tables, settings pages, dashboards, and resource management patterns. Auto-invoked when building page layouts.
Core Polaris Web Components fundamentals including component library structure, design tokens, responsive patterns, and SSR compatibility. Auto-invoked when working with Polaris components.
Internationalization fundamentals for multi-language Shopify themes
| name | Shopify Section Patterns |
| description | Best practices for creating Shopify 2.0 sections with inline CSS and JavaScript |
A complete Shopify section consists of:
{% stylesheet %} tag (optional){% javascript %} tag (optional){% schema %} JSON configuration{%- 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 %}
{% stylesheet %} When:{{ section.settings.color }}{% javascript %} When:{{ section.settings.enable_feature }}{{ section.id }} or other Liquid values{%- 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 -%}
<h3>{{ product.title | escape }}</h3>
<p>{{ product.price | money }}</p>
</a>
</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 %}
{%- 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 -%}
<p>{{ text }}</p>
{%- endif -%}
{%- if button_label != blank and button_link != blank -%}
<a href="{{ button_link }}" class="button">
{{ button_label | escape }}
</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 %}
<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 -%}
<cite>{{ block.settings.author | escape }}</cite>
{%- endif -%}
</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 %}
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 %}
<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 %}
{%- 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
-%}
{%- if collection.products.size > 0 -%}
<!-- Show products -->
{%- else -%}
<p>No products available in this collection.</p>
{%- endif -%}
/* 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);
}
}
<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 %}
<div class="card{% if product.available %} in-stock{% else %} sold-out{% endif %}">
<!-- Card content -->
</div>
{% 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 %}
{% 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.