Theme blocks
Build reusable, nestable blocks any section can host — Theme blocks.
This guide takes you end to end: you’ll create a theme, add a working section the visual editor can place, wire up a setting and a block, pull in an asset and a snippet, then preview your change as a private draft and publish it. By the end you’ll understand how a Sellerlane theme’s files fit together and how the draft-then-publish model protects your live store.
It assumes you’re comfortable editing code. If you only want to rearrange and configure what a theme already ships, the drag-and-drop visual editor is the place to start instead.
A theme is a folder of files that the storefront renders for every page. You edit them in the code editor (Edit code). The folders are fixed:
| Folder | Holds |
|---|---|
layout/ | theme.liquid — the wrapper for every page |
templates/ | One file per page type (index.json, product.json, …) |
sections/ | Reusable section files with a {% schema %}, plus section-group files (header.json, footer.json) |
blocks/ | Reusable theme blocks with their own schema |
snippets/ | Partials included with {% render %} |
assets/ | CSS, JS, images, fonts — referenced with asset_url |
config/ | settings_schema.json and settings_data.json (global settings) |
locales/ | Translation files for the t filter |
For the full breakdown — how a page assembles, JSON vs Liquid templates, the recognised template types — read Theme architecture first.
You have two starting points.
Open Online store → Themes.
On the theme you want to work on, choose Edit code. The code editor opens on that theme’s draft with the file tree on the left.
Editing code never touches the live store — every change lands in the draft until you publish.
From Online store → Themes, use Add theme (top right):
.zip. ZIP imports must use the exact folder and template paths above, or the file is rejected as unsupported. See Import a theme ZIP.The new theme lands in your library as Unpublished; choose Edit code to open it.
A section is a reusable, configurable band of a page. The visual editor can only add a section that declares a preset — without one, the section is reachable from code only.
In the file tree, click the + on the Sections folder. Choose the Liquid format and name it hello (lowercase letters, numbers, hyphens, and underscores only). The editor creates sections/hello.liquid.
Paste a minimal section with markup and a {% schema %}:
<div class="hello" {{ section.shopify_attributes }}> <h2>{{ section.settings.heading }}</h2></div>
{% schema %}{ "name": "Hello", "tag": "section", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Hello there" } ], "presets": [{ "name": "Hello" }]}{% endschema %}Press Save (Ctrl/Cmd + S). The schema is validated on save — an invalid schema blocks the save with a specific error.
The presets array is what makes the section addable. Now open the visual editor, use Add section, and your Hello section appears in the picker. Add it to the home page and you’ll see Hello there render.
The setting you added (heading) is already wired: the schema declares it under settings, and the markup reads it with {{ section.settings.heading }}. The pattern is always the two halves matching:
settings with an id, a type, and a label.section.settings.<id>.Add a second setting — a checkbox — to see the loop end to end:
<div class="hello" {{ section.shopify_attributes }}> <h2>{{ section.settings.heading }}</h2> {% if section.settings.show_subtitle %} <p>Welcome to the store.</p> {% endif %}</div>
{% schema %}{ "name": "Hello", "tag": "section", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Hello there" }, { "type": "checkbox", "id": "show_subtitle", "label": "Show subtitle", "default": true } ], "presets": [{ "name": "Hello" }]}{% endschema %}Save, and the editor’s inspector now shows a Heading field and a Show subtitle toggle for any Hello section. text, richtext, color, image_picker, collection, product, range, and many more input types are available — see Setting types. Many text and resource settings can also bind to dynamic sources so a value pulls from a product field or metafield automatically.
A block is a smaller, repeatable unit inside a section that merchants can add, reorder, and configure. There are two kinds, and a section uses one or the other — never both.
The simplest is a local (section-defined) block: declared inline in the section’s blocks array and rendered by looping section.blocks.
<div class="hello" {{ section.shopify_attributes }}> <h2>{{ section.settings.heading }}</h2> <ul> {% for block in section.blocks %} {% case block.type %} {% when 'point' %} <li {{ block.shopify_attributes }}>{{ block.settings.text }}</li> {% endcase %} {% endfor %} </ul></div>
{% schema %}{ "name": "Hello", "tag": "section", "settings": [ { "type": "text", "id": "heading", "label": "Heading", "default": "Hello there" } ], "blocks": [ { "type": "point", "name": "Point", "settings": [ { "type": "text", "id": "text", "label": "Text" } ]} ], "max_blocks": 6, "presets": [{ "name": "Hello" }]}{% endschema %}Save, reopen the section in the editor, and the + on the section now offers a Point block you can add up to six times.
For reusable theme blocks (files in blocks/, opted into with { "type": "@theme" } and rendered with {% content_for 'blocks' %} instead of a for loop), see Theme blocks. A single section can’t mix local blocks with theme blocks.
Assets are the files in assets/ — CSS, JS, images, fonts. Reference one with the asset_url filter, which returns a versioned, CDN-served URL so each published version is cached immutably.
In the code editor, open the Assets folder, choose +, and Create blank asset → CSS, named hello.css. Add a rule:
.hello { text-align: center; padding: 2rem; }In sections/hello.liquid, load it with the stylesheet_tag filter, which wraps the URL in a <link>:
{{ 'hello.css' | asset_url | stylesheet_tag }}Snippets are partials in snippets/ that you reuse across sections with {% render %}. A snippet runs in an isolated scope — it sees only the variables you pass in.
Create snippets/badge.liquid:
<span class="badge">{{ label }}</span>Render it from the section, passing the variable explicitly:
{% render 'badge', label: section.settings.heading %}Everything so far lives in the draft. The draft is private to you and your staff — shoppers never see it.
Save every file you changed. Only saved draft content is included when you publish.
From Online store → Themes, choose Preview on the theme (or Preview in the editor’s top bar) to open the draft in a new tab without going live. Click through your pages and confirm the section, settings, blocks, and styles look right.
When you’re happy, choose Publish in the editor’s top bar. In the Publish theme dialog, optionally add a Release label (for example Summer update) so you can identify the snapshot later, then confirm.
Publishing creates a new live version from your saved draft and switches the storefront to it. The draft stays editable, so you can keep working immediately.
Every theme version carries one of three statuses — DRAFT, LIVE, or ARCHIVED:
Asset URLs are pinned to the version too — a live request serves the live version’s assets from the CDN, while a verified editor preview serves the draft’s assets with no-cache headers — so a publish swaps the whole bundle atomically and a rollback restores the exact files that shipped. See Manage themes for the full version lifecycle.
You’ve built a section, wired settings and a block, and shipped it safely. From here:
Theme blocks
Build reusable, nestable blocks any section can host — Theme blocks.
Section groups
Share the header, footer, and aside bands across every page — Section groups.
Locales & translation
Move hard-coded strings into the t filter — Locales and translation.
Storefront APIs
Add live behaviour with the Cart, Predictive search, and Product recommendations APIs.
Reference: Theme architecture · Section schema · Setting types · Theme assets (CSS/JS) · Dynamic sources · Liquid objects · Liquid tags · Liquid filters
Related: Editing theme code · Themes & the visual editor · Import a theme ZIP · Manage themes