shopify-theme-development
Build and customize Shopify themes using Liquid templating, JSON sections, dynamic blocks, and theme app extensions for added functionality
What this skill does
# Shopify Theme Development
## Overview
Build and customize Shopify themes using Liquid templating, JSON templates, sections and blocks for merchant-customizable layouts, and theme app extensions for app integrations. This skill covers the Shopify theme architecture (Online Store 2.0), the Shopify CLI development workflow, performance optimization with lazy loading and critical CSS, and patterns for building flexible sections that merchants can configure through the theme editor.
## When to Use This Skill
- When building a new Shopify theme from scratch or forking Dawn
- When creating custom sections and blocks for the theme editor
- When implementing product pages, collection grids, or cart functionality in Liquid
- When optimizing a Shopify theme for Core Web Vitals and speed
- When building theme app extensions to inject app content into themes
## Core Instructions
1. **Set up the development environment with Shopify CLI**
```bash
# Install Shopify CLI
npm install -g @shopify/cli @shopify/theme
# Initialize a new theme (or clone Dawn)
shopify theme init my-theme
# Start development server with hot reload
shopify theme dev --store=your-store.myshopify.com
```
Theme directory structure (Online Store 2.0):
```
my-theme/
├── assets/ # CSS, JS, images
├── config/ # settings_schema.json, settings_data.json
├── layout/ # theme.liquid (main layout)
├── locales/ # Translation files
├── sections/ # Sections (reusable, merchant-configurable)
├── snippets/ # Partials (reusable Liquid fragments)
└── templates/ # JSON templates referencing sections
├── product.json
├── collection.json
└── index.json
```
2. **Create a JSON template with sections**
```json
// templates/product.json
{
"sections": {
"main": {
"type": "main-product",
"settings": {}
},
"recommendations": {
"type": "product-recommendations",
"settings": {
"heading": "You may also like",
"products_to_show": 4
}
},
"reviews": {
"type": "product-reviews",
"settings": {}
}
},
"order": ["main", "recommendations", "reviews"]
}
```
3. **Build a customizable product section with blocks**
```liquid
{% comment %}
sections/main-product.liquid
{% endcomment %}
<section class="product-section" data-section-id="{{ section.id }}">
<div class="product-grid">
<div class="product-media">
{% for media in product.media %}
{% case media.media_type %}
{% when 'image' %}
<div class="product-media-item {% if forloop.first %}active{% endif %}">
{{ media | image_url: width: 800 | image_tag:
loading: 'lazy',
widths: '200,400,600,800,1000',
sizes: '(min-width: 768px) 50vw, 100vw',
class: 'product-image'
}}
</div>
{% when 'video' %}
<div class="product-media-item">
{{ media | video_tag: autoplay: false, controls: true }}
</div>
{% endcase %}
{% endfor %}
</div>
<div class="product-info">
{% for block in section.blocks %}
{% case block.type %}
{% when 'title' %}
<h1 class="product-title" {{ block.shopify_attributes }}>
{{ product.title }}
</h1>
{% when 'price' %}
<div class="product-price" {{ block.shopify_attributes }}>
{% if product.compare_at_price > product.price %}
<s class="price-compare">{{ product.compare_at_price | money }}</s>
{% endif %}
<span class="price-current">{{ product.price | money }}</span>
{% if product.compare_at_price > product.price %}
<span class="price-badge">Sale</span>
{% endif %}
</div>
{% when 'variant_picker' %}
<div class="variant-picker" {{ block.shopify_attributes }}>
{% for option in product.options_with_values %}
<fieldset class="option-group">
<legend>{{ option.name }}</legend>
{% for value in option.values %}
<label class="option-label">
<input
type="radio"
name="{{ option.name }}"
value="{{ value }}"
{% if option.selected_value == value %}checked{% endif %}
>
<span>{{ value }}</span>
</label>
{% endfor %}
</fieldset>
{% endfor %}
</div>
{% when 'buy_buttons' %}
<div class="buy-buttons" {{ block.shopify_attributes }}>
{% form 'product', product %}
<input type="hidden" name="id" value="{{ product.selected_or_first_available_variant.id }}">
<div class="quantity-selector">
<label for="quantity">Quantity</label>
<input type="number" id="quantity" name="quantity" value="1" min="1">
</div>
<button
type="submit"
class="btn btn-primary add-to-cart"
{% unless product.selected_or_first_available_variant.available %}disabled{% endunless %}
>
{% if product.selected_or_first_available_variant.available %}
Add to cart — {{ product.selected_or_first_available_variant.price | money }}
{% else %}
Sold out
{% endif %}
</button>
{% endform %}
</div>
{% when 'description' %}
<div class="product-description" {{ block.shopify_attributes }}>
{{ product.description }}
</div>
{% when 'custom_text' %}
<div class="custom-text" {{ block.shopify_attributes }}>
{{ block.settings.text }}
</div>
{% endcase %}
{% endfor %}
</div>
</div>
</section>
{% schema %}
{
"name": "Product Page",
"tag": "section",
"class": "section-product",
"blocks": [
{
"type": "title",
"name": "Title",
"limit": 1
},
{
"type": "price",
"name": "Price",
"limit": 1
},
{
"type": "variant_picker",
"name": "Variant Picker",
"limit": 1
},
{
"type": "buy_buttons",
"name": "Buy Buttons",
"limit": 1
},
{
"type": "description",
"name": "Description",
"limit": 1
},
{
"type": "custom_text",
"name": "Custom Text",
"settings": [
{
"type": "richtext",
"id": "text",
"label": "Text"
}
]
}
],
"presets": [
{
"name": "Product Page",
"blocks": [
{ "type": "title" },
{ "type": "price" },
{ "type": "variant_picker" },
{ "type": "buy_buttons" },
{ "type": "description" }
]
}
]
}
{% endschema %}
```
4. **Implement AJAX cart with the Cart API**
```javascript
// assets/cart.js
class CartManager {
async addItem(variantId, quantity = 1) {
const response = await fetch('/cart/add.js', {
method: 'POST',
Related in platform-shopify
shopify-metafields
IncludedStore custom data on any Shopify resource — products, orders, customers — using typed metafield definitions accessible from Liquid and the Storefront API
shopify-admin-api
IncludedAutomate Shopify store operations — products, orders, inventory, and customers — using the GraphQL Admin API with bulk operation support
shopify-app-development
IncludedBuild embedded Shopify apps using the Remix framework, App Bridge for UI integration, Polaris components, and OAuth authentication flow
shopify-storefront-api
IncludedBuild a headless Shopify frontend using the GraphQL Storefront API for product queries, cart management, and checkout with the Buy SDK
shopify-webhooks
IncludedRegister, verify, and reliably process Shopify webhook events for orders, inventory, and customers with HMAC validation and idempotency handling
shopify-checkout-extensions
IncludedCustomize Shopify's checkout with UI extensions for upsells and custom fields, plus Shopify Functions for serverless discount and shipping logic