Skip to content

Sections and blocks

How you split a page into sections and blocks decides how much a seller can change without touching code.

Pick the right granularity

A section should be one meaningful area of a page: a slideshow, a featured collection, a FAQ list. Split further and sellers spend their time reassembling a page that should have arrived whole; split less and they can't reorder or remove the parts they don't want.

Use blocks for the repeating items inside a section, and only when the count is genuinely variable. A slideshow's slides are blocks. A product card's price and title are not; they belong to the section's markup, driven by settings.

json
"blocks": [
  { "type": "slide", "label": "t:sections.slideshow.slide", "limit": 8, "settings": [] }
]

Choose where a section is rendered

  • In a JSON template when sellers should be able to add, remove, and reorder it, or place it more than once with different settings.
  • Statically with {% section %} when it belongs on every page and its position is fixed. Headers, footers, and announcement bars belong here.

Static sections read their data from config/settings_data.json and share one configuration everywhere, so don't use them for anything a seller would want to vary per page.

Constrain what you expose

Use the section schema to keep configurations sane:

  • templates restricts a section to the pages it makes sense on, instead of letting it be added to the cart page by accident.
  • limit caps how many times a section can be added to one template.
  • max_blocks and per-block limit keep a carousel from becoming forty slides.
json
{
  "label": "t:sections.featured_collection.label",
  "templates": ["index", "collection"],
  "limit": 2,
  "max_blocks": 8
}

Give settings good defaults

A section dropped onto a page should look finished before the seller touches it. Set a default on every setting that has a reasonable one, and render a placeholder when a picker is still empty:

liquid
{% if section.settings.image.src %}
  <img src="{{ section.settings.image.src }}" alt="{{ section.settings.image.alt }}">
{% else %}
  {% render 'misc.image-fallback' %}
{% endif %}

Do the same for blocks. A section with no blocks yet should still render something the seller can see and click.

Keep section files readable

Move a block's markup into its own snippet once it grows past a handful of lines, one snippet per block type, named block.<type>.liquid:

liquid
{% for slide in section.blocks %}
  {% render 'block.slide' %}
{% endfor %}

The section file then reads as a layout of its parts rather than a wall of markup.

Name things for the seller

label is what a seller reads in the editor, not what you call the file. Use t: locale keys so those names translate, and keep them concrete: "Slide", "Collection", "Call to action".

json
{ "type": "cta", "label": "t:common.headers.button" }