Section Schema
Define settings for sections using JSON schema inside the schema tag.
Every section needs a schema. The schema tells the visual editor what settings to show in the sidebar. Merchants change these settings to control the section without editing code.
How it works
Put a {% schema %} block at the bottom of your section template. Inside it, write a JSON object that lists the settings you want:
{% schema %}
{
"name": "Hero Banner",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Welcome to our store"
}
]
}
{% endschema %}The visual editor reads this JSON and builds a form. When the merchant types a new heading, you can use it in the template:
<h1>{{ section.settings.heading }}</h1>Schema structure
The top level of the schema object has these fields:
| Field | Required | Description |
|---|---|---|
name | yes | The name shown in the visual editor sidebar |
tag | no | The HTML tag for the section wrapper (default: section) |
class | no | A CSS class added to the wrapper element |
settings | no | An array of setting definitions |
blocks | no | An array of block type definitions |
presets | no | Default configurations for adding the section |
max_blocks | no | The maximum number of blocks allowed |
Settings
Each setting is an object with at least three fields:
| Field | Required | Description |
|---|---|---|
type | yes | The kind of input (see table below) |
id | yes | A unique key used to access the value in the template |
label | yes | The label shown in the editor form |
default | no | The starting value before the merchant changes it |
info | no | Help text shown below the input |
placeholder | no | Placeholder text for text inputs |
group | no | Assign this setting to a named group (see Groups below) |
condition | no | Show this setting only when another field matches a value (see Conditional fields) |
hidden | no | Set to true to keep this field in the data but hide it from the editor form |
Setting types
These are all the input types you can use in a schema:
Text inputs
{ "type": "text", "id": "heading", "label": "Heading", "default": "Hello" }{ "type": "textarea", "id": "body", "label": "Body text" }{ "type": "richtext", "id": "content", "label": "Content" }The richtext type gives the merchant a formatting toolbar. The value is an HTML string.
Numbers
{ "type": "number", "id": "speed", "label": "Scroll speed", "default": 5 }{
"type": "range",
"id": "columns",
"label": "Columns",
"min": 1,
"max": 6,
"step": 1,
"default": 3
}The range type shows a slider. You must set min, max, and step.
Boolean
{ "type": "checkbox", "id": "show_price", "label": "Show price", "default": true }Selection
{
"type": "select",
"id": "layout",
"label": "Layout",
"options": [
{ "value": "grid", "label": "Grid" },
{ "value": "list", "label": "List" },
{ "value": "carousel", "label": "Carousel" }
],
"default": "grid"
}{
"type": "radio",
"id": "alignment",
"label": "Text alignment",
"options": [
{ "value": "left", "label": "Left" },
{ "value": "center", "label": "Center" },
{ "value": "right", "label": "Right" }
],
"default": "left"
}Color
{ "type": "color", "id": "text_color", "label": "Text color", "default": "#000000" }{ "type": "color_background", "id": "bg", "label": "Background" }The color_background type supports both solid colors and gradients.
Media
{ "type": "image_picker", "id": "image", "label": "Image" }{ "type": "video_url", "id": "video", "label": "Video URL" }The image_picker returns an image object. Use img_url or image_tag to display it.
Resource pickers
{ "type": "collection", "id": "collection", "label": "Collection" }{ "type": "product", "id": "featured", "label": "Featured product" }{ "type": "product_list", "id": "products", "label": "Products" }{ "type": "page", "id": "page", "label": "Page" }These let the merchant pick a product, collection, or page from the admin. The value is the full object, so you can access all its properties in the template.
Other types
{ "type": "url", "id": "link", "label": "Link URL" }{ "type": "font_picker", "id": "heading_font", "label": "Heading font" }{ "type": "html", "id": "custom", "label": "Custom HTML" }{ "type": "quill", "id": "code", "label": "Custom Quill code" }Full example
A banner section with an image, heading, button, and color controls:
<div class="banner" style="background: {{ section.settings.bg_color }}">
{% if section.settings.image %}
{{ section.settings.image | image_tag: class: 'banner__image' }}
{% endif %}
<div class="banner__content">
<h2 style="color: {{ section.settings.text_color }}">
{{ section.settings.heading }}
</h2>
{% if section.settings.button_text != blank %}
<a href="{{ section.settings.button_link }}" class="btn">
{{ section.settings.button_text }}
</a>
{% endif %}
</div>
</div>
{% schema %}
{
"name": "Banner",
"settings": [
{ "type": "image_picker", "id": "image", "label": "Background image" },
{ "type": "text", "id": "heading", "label": "Heading", "default": "Welcome" },
{ "type": "text", "id": "button_text", "label": "Button text" },
{ "type": "url", "id": "button_link", "label": "Button link" },
{ "type": "color", "id": "bg_color", "label": "Background color", "default": "#f5f5f5" },
{ "type": "color", "id": "text_color", "label": "Text color", "default": "#000000" }
],
"presets": [{ "name": "Banner", "category": "Image" }]
}
{% endschema %}Groups
By default, all settings appear in a flat list. For sections with many settings, you can organise them into collapsible groups.
Define a groups array at the top level of the schema, then assign each setting to a group using the group field:
{% schema %}
{
"name": "Hero Banner",
"groups": [
{ "id": "style", "label": "Style" },
{ "id": "advanced", "label": "Advanced", "collapsed": true }
],
"settings": [
{ "type": "text", "id": "heading", "label": "Heading" },
{ "type": "text", "id": "body", "label": "Body text" },
{ "type": "select", "id": "padding", "label": "Section padding", "group": "style",
"options": [
{ "value": "compact", "label": "Compact" },
{ "value": "default", "label": "Default" },
{ "value": "spacious", "label": "Spacious" }
],
"default": "default"
},
{ "type": "select", "id": "btn_size", "label": "Button size", "group": "advanced",
"options": [
{ "value": "sm", "label": "Small" },
{ "value": "default", "label": "Default" },
{ "value": "lg", "label": "Large" }
],
"default": "default"
}
]
}
{% endschema %}Group properties
| Field | Required | Description |
|---|---|---|
id | yes | A unique key that settings reference with group |
label | yes | The heading shown in the editor sidebar |
collapsed | no | Set to true to collapse the group by default (default: true) |
Settings without a group field appear at the top of the panel, above any groups. Groups with no visible settings are hidden automatically.
Conditional fields
Show a setting only when another field has a specific value. This keeps the settings panel clean by hiding fields that are not relevant to the current configuration.
{% schema %}
{
"name": "Media Section",
"settings": [
{ "type": "select", "id": "media_type", "label": "Media type",
"options": [
{ "value": "image", "label": "Image" },
{ "value": "video", "label": "Video" }
],
"default": "image"
},
{ "type": "image_picker", "id": "image", "label": "Image",
"condition": { "field": "media_type", "eq": "image" }
},
{ "type": "video_url", "id": "video", "label": "Video URL",
"condition": { "field": "media_type", "eq": "video" }
}
]
}
{% endschema %}When the merchant picks "Image", only the image picker shows. When they pick "Video", only the video URL field shows.
Condition operators
| Operator | Description |
|---|---|
eq | Show when the field equals this value |
neq | Show when the field does not equal this value |
{ "type": "color", "id": "overlay_color", "label": "Overlay colour",
"condition": { "field": "show_overlay", "neq": false }
}The field value must be the id of another setting in the same schema.
Hidden fields
Set "hidden": true on a setting to keep it in the section data without showing it in the editor form. The field still has a default value, presets can set it, and the template can read it. It just does not appear as a control.
{ "type": "select", "id": "layout", "label": "Layout", "hidden": true, "default": "centered",
"options": [
{ "value": "centered", "label": "Centered" },
{ "value": "split", "label": "Split" }
]
}This is useful when a preset controls the value. The merchant picks a style from the preset selector, which sets the hidden field internally. There is no need for a separate dropdown that does the same thing.