Ready examples
Recipes to copy. Each block shows the file it goes in and passes the store's
check. After creating a section, add it in Customize theme > Sections of the
page or in templates/<page>.json.
Promotion banner
A banner with a title, text and a button, all editable in Customize theme.
<section class="promo">
<div class="promo-in">
<p class="promo-tag">{{ section.settings.tag }}</p>
<h2>{{ section.settings.title }}</h2>
<p>{{ section.settings.text }}</p>
{%- if section.settings.button_url != blank -%}
<a class="promo-btn" href="{{ section.settings.button_url }}">{{ section.settings.button_label }}</a>
{%- endif -%}
</div>
</section>
{% schema %}
{
"name": "Promotion banner",
"settings": [
{ "id": "tag", "type": "text", "label": "Tag", "default": "This week only" },
{ "id": "title", "type": "text", "label": "Title", "default": "Black Friday: up to 50% off" },
{ "id": "text", "type": "textarea", "label": "Text", "default": "Kits, VIPs and cosmetics on sale." },
{ "id": "button_label", "type": "text", "label": "Button text", "default": "See the deals" },
{ "id": "button_url", "type": "url", "label": "Button link", "default": "/loja" }
]
}
{% endschema %}
.promo { padding: 48px 20px; background: linear-gradient(120deg, hsl(var(--primary)), #1d4ed8); color: #fff; }
.promo-in { max-width: 960px; margin: 0 auto; }
.promo-tag { display: inline-block; padding: 4px 10px; border-radius: 999px; background: rgba(255, 255, 255, .18); font-weight: 700; font-size: 13px; }
.promo h2 { margin: 12px 0 8px; font-size: clamp(28px, 4vw, 44px); }
.promo-btn { display: inline-block; margin-top: 12px; padding: 12px 22px; border-radius: 12px; background: #f5b544; color: #1c1305; font-weight: 700; text-decoration: none; }
Category showcase
The products of a category, with price, sale and a buy button.
{% load products, category: section.settings.category, limit: section.settings.count as items %}
<section class="showcase">
<h2>{{ section.settings.title }}</h2>
<div class="showcase-grid">
{%- for p in items -%}
<article class="showcase-card">
<a href="{{ p.url }}">
{%- if p.image -%}<img src="{{ p.image }}" alt="{{ p.name }}" loading="lazy">{%- endif -%}
<h3>{{ p.name }}</h3>
</a>
<p class="showcase-price">
{%- if p.on_sale -%}<s>{{ p.original_price | money }}</s> {% endif -%}
<strong>{{ p.price | money }}</strong>
</p>
{%- if p.sold_out -%}
<span class="showcase-off">{{ 'product.sold_out' | t }}</span>
{%- else -%}
<button type="button" data-hystore-add-to-cart="{{ p.id }}">{{ 'product.add' | t }}</button>
{%- endif -%}
</article>
{%- else -%}
<p>{{ 'showcase.empty' | t }}</p>
{%- endfor -%}
</div>
</section>
{% schema %}
{
"name": "Category showcase",
"settings": [
{ "id": "title", "type": "text", "label": "Title", "default": "Kits" },
{ "id": "category", "type": "text", "label": "Category slug", "default": "kits" },
{ "id": "count", "type": "range", "label": "How many", "min": 2, "max": 24, "default": 8 }
]
}
{% endschema %}
The slug is the end of the category's address in the store (/loja/survival/kits
has the slug kits). The texts product.add, product.sold_out and
showcase.empty live in the language files:
{
"product": { "add": "Buy", "sold_out": "Sold out" },
"showcase": { "empty": "No products here yet." }
}
Countdown
The store fills in the numbers by itself, with no JavaScript in the theme.
<section class="countdown" data-hystore-countdown="{{ section.settings.ends_at }}">
<h2>{{ section.settings.title }}</h2>
<div class="countdown-row">
<span><b data-hystore-days>0</b> {{ 'time.days' | t }}</span>
<span><b data-hystore-hours>0</b> {{ 'time.hours' | t }}</span>
<span><b data-hystore-minutes>0</b> {{ 'time.minutes' | t }}</span>
<span><b data-hystore-seconds>0</b> {{ 'time.seconds' | t }}</span>
</div>
</section>
{% schema %}
{
"name": "Countdown",
"settings": [
{ "id": "title", "type": "text", "label": "Title", "default": "The new season starts in" },
{ "id": "ends_at", "type": "text", "label": "Date and time (UTC)", "default": "2026-12-24T23:59:00Z" }
]
}
{% endschema %}
Server IP and players online
{% load server_status as status %}
<section class="server-bar">
<button type="button" class="server-ip" data-hystore-copy="{{ store.ip }}">{{ store.ip }}</button>
{%- if status and status.online -%}
<span class="server-on">{{ status.players_online }}/{{ status.players_max }} {{ 'server.online' | t }}</span>
{%- else -%}
<span class="server-off">{{ 'server.offline' | t }}</span>
{%- endif -%}
<hystore-online-players></hystore-online-players>
</section>
{% schema %}
{ "name": "Server bar", "settings": [] }
{% endschema %}
Clicking the IP copies the address. The store fills <hystore-online-players>
with the players online.
Top buyers of the month
{% load ranking, period: 'month', limit: 5 as top %}
<section class="top-buyers">
<h2>{{ section.settings.title }}</h2>
<ol>
{%- for row in top -%}
<li>
<img src="{{ row.nick | skin_url: 48 }}" alt="" width="48" height="48">
<span>{{ row.position }}. {{ row.nick }}</span>
<b>{{ row.total_spent | money }}</b>
</li>
{%- endfor -%}
</ol>
</section>
{% schema %}
{
"name": "Top buyers",
"settings": [{ "id": "title", "type": "text", "label": "Title", "default": "Top of the month" }]
}
{% endschema %}
Frequently asked questions
An accordion with questions the store owner adds as blocks.
<section class="faq" data-hystore-accordion="single">
<h2>{{ section.settings.title }}</h2>
{%- for block in section.blocks -%}
<div class="faq-item" data-hystore-accordion-item>
<button type="button" data-hystore-accordion-toggle>{{ block.settings.question }}</button>
<div class="faq-answer" data-hystore-accordion-panel>{{ block.settings.answer }}</div>
</div>
{%- endfor -%}
</section>
{% schema %}
{
"name": "FAQ",
"settings": [{ "id": "title", "type": "text", "label": "Title", "default": "Questions" }],
"blocks": [
{
"type": "question",
"name": "Question",
"settings": [
{ "id": "question", "type": "text", "label": "Question" },
{ "id": "answer", "type": "textarea", "label": "Answer" }
]
}
]
}
{% endschema %}
Theme colours and options
General settings live in theme.json and become fields in Customize theme:
{
"name": "My theme",
"version": "1.0.0",
"color_modes": ["dark", "light"],
"settings": [
{ "id": "accent", "type": "color", "label": "Accent colour", "default": "#f5b544" },
{ "id": "radius", "type": "range", "label": "Roundness", "min": 0, "max": 28, "default": 14 }
]
}
Colours and numbers become CSS variables at the theme's root:
.button { background: var(--theme-accent); border-radius: calc(var(--theme-radius) * 1px); }
html:not(.dark) .card { background: #fff; color: #0b1526; }
html.dark .card { background: #0d1524; color: #e8eef8; }
And any general setting shows in Liquid as {{ settings.accent }}.
Switch colour mode and language
<div class="header-tools">
<button type="button" data-hystore-color-mode="toggle">{{ 'header.theme' | t }}</button>
<button type="button" data-hystore-language="pt">PT</button>
<button type="button" data-hystore-language="en">EN</button>
<button type="button" data-hystore-language="es">ES</button>
<button type="button" data-hystore-open="cart">{{ 'header.cart' | t }} (<span data-hystore-cart-count>0</span>)</button>
<hystore-account></hystore-account>
</div>
Use it in the layout with {% render 'header-tools' %}.
More
- The theme guide lists every data source, filter, ready-made block and interactive piece.
- For JavaScript (wheel, quiz, calculator), see Isolated apps.
- The Base, Aurora, Celeste and Prisma themes are great to learn from: start one in the dashboard and open its files in the editor.
