Create a Theme
Learn how to create a Shoplazza theme from scratch.
Prerequisites
Before you start, make sure you have:
- ✅ A Shoplazza Partner account
- ✅ Basic knowledge of HTML, CSS, and JavaScript
- ✅ Familiarity with Liquid templating language
- ✅ Text editor or IDE (VS Code recommended)
- ✅ Shoplazza CLI installed
Step 1: Set Up Development Environment
Install Shoplazza CLI
npm install -g @shoplazza/cli
Authenticate
shoplazza login
Create Development Store
- Log in to your Partner Dashboard
- Navigate to Stores > Add store
- Create a development store for testing
Step 2: Initialize Theme
Create Theme Directory
shoplazza theme init my-custom-theme
cd my-custom-theme
This creates a basic theme structure:
my-custom-theme/
├── assets/
│ ├── application.css
│ ├── application.js
│ └── theme.css
├── config/
│ ├── settings_data.json
│ └── settings_schema.json
├── layout/
│ └── theme.liquid
├── locales/
│ └── en.default.json
├── sections/
│ ├── header.liquid
│ ├── footer.liquid
│ └── product-template.liquid
├── snippets/
│ └── product-card.liquid
└── templates/
├── index.liquid
├── product.liquid
├── collection.liquid
└── page.liquid
Step 3: Build Your Layout
Create Base Layout
Edit layout/theme.liquid:
<!DOCTYPE html>
<html lang="{{ shop.locale }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ page_title }}{% if current_page != 1 %} - {{ 'general.meta.page' | t: page: current_page }}{% endif %}</title>
{% if page_description %}
<meta name="description" content="{{ page_description | escape }}">
{% endif %}
{{ content_for_header }}
{{ 'application.css' | asset_url | stylesheet_tag }}
{{ 'theme.css' | asset_url | stylesheet_tag }}
</head>
<body class="template-{{ template.name }}">
{% section 'header' %}
<main role="main">
{{ content_for_layout }}
</main>
{% section 'footer' %}
{{ 'application.js' | asset_url | script_tag }}
</body>
</html>
Step 4: Create Templates
Product Template
Create templates/product.liquid:
{% assign current_variant = product.selected_or_first_available_variant %}
<div class="product-page">
<div class="product-gallery">
<img src="{{ current_variant.featured_image | img_url: '800x' }}"
alt="{{ product.title }}">
</div>
<div class="product-info">
<h1>{{ product.title }}</h1>
<div class="product-price">
<span class="price">{{ current_variant.price | money }}</span>
{% if current_variant.compare_at_price > current_variant.price %}
<span class="compare-price">{{ current_variant.compare_at_price | money }}</span>
{% endif %}
</div>
<div class="product-description">
{{ product.description }}
</div>
{% form 'product', product %}
<select name="id">
{% for variant in product.variants %}
<option value="{{ variant.id }}"
{% if variant == current_variant %}selected{% endif %}>
{{ variant.title }} - {{ variant.price | money }}
</option>
{% endfor %}
</select>
<button type="submit" name="add">
Add to Cart
</button>
{% endform %}
</div>
</div>
Collection Template
Create templates/collection.liquid:
<div class="collection-page">
<header class="collection-header">
<h1>{{ collection.title }}</h1>
{% if collection.description != blank %}
<div class="collection-description">
{{ collection.description }}
</div>
{% endif %}
</header>
<div class="product-grid">
{% for product in collection.products %}
{% render 'product-card', product: product %}
{% endfor %}
</div>
{% if paginate.pages > 1 %}
{% render 'pagination', paginate: paginate %}
{% endif %}
</div>
Step 5: Create Sections
Header Section
Create sections/header.liquid:
<header class="site-header">
<nav class="main-navigation">
<a href="/" class="logo">
{% if section.settings.logo %}
<img src="{{ section.settings.logo | img_url: '200x' }}"
alt="{{ shop.name }}">
{% else %}
{{ shop.name }}
{% endif %}
</a>
<ul class="nav-menu">
{% for link in linklists[section.settings.menu].links %}
<li>
<a href="{{ link.url }}">{{ link.title }}</a>
</li>
{% endfor %}
</ul>
<div class="header-icons">
<a href="/search">Search</a>
<a href="/account">Account</a>
<a href="/cart">Cart ({{ cart.item_count }})</a>
</div>
</nav>
</header>
{% schema %}
{
"name": "Header",
"settings": [
{
"type": "image_picker",
"id": "logo",
"label": "Logo"
},
{
"type": "link_list",
"id": "menu",
"label": "Menu",
"default": "main-menu"
}
]
}
{% endschema %}
Step 6: Create Snippets
Product Card Snippet
Create snippets/product-card.liquid:
<div class="product-card">
<a href="{{ product.url }}">
<div class="product-card__image">
{% if product.featured_image %}
<img src="{{ product.featured_image | img_url: '400x' }}"
alt="{{ product.title }}">
{% endif %}
</div>
<div class="product-card__info">
<h3 class="product-card__title">{{ product.title }}</h3>
<div class="product-card__price">
{{ product.price | money }}
{% if product.compare_at_price > product.price %}
<span class="compare-price">
{{ product.compare_at_price | money }}
</span>
{% endif %}
</div>
</div>
</a>
</div>
Step 7: Add Styling
Main Stylesheet
Edit assets/theme.css:
/* Variables */
:root {
--color-primary: #000;
--color-secondary: #666;
--color-background: #fff;
--spacing-unit: 1rem;
--max-width: 1200px;
}
/* Layout */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
color: var(--color-primary);
line-height: 1.6;
margin: 0;
padding: 0;
}
.container {
max-width: var(--max-width);
margin: 0 auto;
padding: 0 var(--spacing-unit);
}
/* Header */
.site-header {
border-bottom: 1px solid #eee;
padding: 1rem 0;
}
.main-navigation {
display: flex;
align-items: center;
justify-content: space-between;
max-width: var(--max-width);
margin: 0 auto;
padding: 0 var(--spacing-unit);
}
.nav-menu {
display: flex;
gap: 2rem;
list-style: none;
margin: 0;
padding: 0;
}
.nav-menu a {
text-decoration: none;
color: var(--color-primary);
}
/* Product Grid */
.product-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 2rem;
padding: 2rem 0;
}
.product-card {
border: 1px solid #eee;
border-radius: 8px;
overflow: hidden;
transition: box-shadow 0.3s ease;
}
.product-card:hover {
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.product-card__image img {
width: 100%;
height: auto;
display: block;
}
.product-card__info {
padding: 1rem;
}
.product-card__title {
margin: 0 0 0.5rem;
font-size: 1.1rem;
}
.product-card__price {
font-weight: bold;
}
/* Product Page */
.product-page {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
padding: 3rem 0;
max-width: var(--max-width);
margin: 0 auto;
}
@media (max-width: 768px) {
.product-page {
grid-template-columns: 1fr;
}
}
Step 8: Add JavaScript
Edit assets/application.js:
// Cart functionality
function addToCart(variantId, quantity = 1) {
fetch('/cart/add.js', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: variantId,
quantity: quantity
})
})
.then(response => response.json())
.then(data => {
updateCartCount();
showNotification('Added to cart!');
})
.catch(error => {
console.error('Error:', error);
showNotification('Error adding to cart', 'error');
});
}
// Update cart count
function updateCartCount() {
fetch('/cart.js')
.then(response => response.json())
.then(cart => {
document.querySelector('.cart-count').textContent = cart.item_count;
});
}
// Initialize
document.addEventListener('DOMContentLoaded', () => {
// Handle add to cart forms
document.querySelectorAll('form[action="/cart/add"]').forEach(form => {
form.addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(form);
const variantId = formData.get('id');
addToCart(variantId);
});
});
});
Step 9: Test Your Theme
Start Development Server
shoplazza theme serve
Preview Your Theme
Open the provided URL to see your theme in action.
Test Responsive Design
Test on different devices and screen sizes.
Step 10: Deploy Your Theme
Upload to Store
shoplazza theme push
Publish Theme
- Go to your store admin
- Navigate to Online Store > Themes
- Find your theme and click Publish
Best Practices
- Performance: Optimize images and minimize CSS/JS
- Accessibility: Use semantic HTML and ARIA labels
- SEO: Include proper meta tags and structured data
- Mobile-First: Design for mobile devices first
- Testing: Test thoroughly before publishing