Skip to main content

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

  1. Log in to your Partner Dashboard
  2. Navigate to Stores > Add store
  3. 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

  1. Go to your store admin
  2. Navigate to Online Store > Themes
  3. Find your theme and click Publish

Best Practices

  1. Performance: Optimize images and minimize CSS/JS
  2. Accessibility: Use semantic HTML and ARIA labels
  3. SEO: Include proper meta tags and structured data
  4. Mobile-First: Design for mobile devices first
  5. Testing: Test thoroughly before publishing

Next Steps