Skip to main content

Settings System

Define configurable options for themes and sections. The same setting types are used in both contexts, but how initial values are defined differs.

Key Difference

Theme settings use "default" on each setting for initial values. Section settings never use "default" -- all initial values live in presets. The validator will reject section schemas that contain "default" fields.


Section Schema Structure

Each section ends with a {% schema %} block containing settings, blocks, and presets:

{% schema %}
{
"name": "Section Name",
"category": "cta",
"tag": "section",
"settings": [...],
"blocks": [...],
"presets": [
{
"name": "Default",
"settings": {
"title": "Hello World",
"bgcolor": "",
"show_date": true
}
}
]
}
{% endschema %}

Presets are the single source of truth. When a section is added to a page, the first preset's values are used as the initial settings. Every non-display setting must have a corresponding entry in the preset.


Theme Settings Schema

Theme-level settings live in config/settings_schema.json. Unlike sections, theme settings use "default" directly on each setting:

{
"name": "Colors",
"settings": [
{
"type": "color",
"id": "primary_color",
"label": "Primary Color",
"default": "#3B82F6"
},
{
"type": "color",
"id": "text_color",
"label": "Text Color",
"default": "#1F2937"
}
]
}

The stored values go into config/settings_data.json. The "default" in the schema is the initial/fallback value.


Setting Types

All types below work in both section and theme settings. Examples show the setting definition only -- remember that for sections, initial values go in presets, not "default".

Display-Only Types

These types don't store values -- they organize and explain settings in the admin UI.

Section divider with label text.

{
"type": "header",
"content": "Text Colors"
}

info

Informational text box with helpful context.

{
"type": "info",
"content": "Used when sections have 'Light Text' enabled (for dark backgrounds)"
}

text

Simple text input or textarea.

{
"type": "text",
"id": "title",
"label": "Title",
"nb_rows": 1
}
OptionDescription
nb_rows1 = input, 2+ = textarea
htmltrue = rich text editor (Trix)
line_breakAllow line breaks

Live Preview -- Use .attr accessor:

<h2 {{ section.settings.title.attr }}>{{ section.settings.title }}</h2>

color

Color picker (no transparency).

{
"type": "color",
"id": "bgcolor",
"label": "Background Color"
}

Live Preview -- Use CSS variables:

{% capture section_style %}--bgcolor: {{ section.settings.bgcolor }};{% endcapture %}
{% section_wrapper 'section' style: section_style data-css-vars: 'bgcolor' %}
<div style="background-color: var(--bgcolor);">

color_alpha

Color picker with transparency.

{
"type": "color_alpha",
"id": "overlay_color",
"label": "Overlay Color"
}

Value format: {"color": "#RRGGBB", "alpha": 0-100}

Liquid Filter:

{{ section.settings.overlay_color | color_alpha_to_rgba }}
<!-- Output: rgba(31, 41, 55, 0.80) -->

image

Image picker from asset library.

{
"type": "image",
"id": "background_image",
"label": "Background Image"
}

Liquid Filter -- Use image_url with size:

<img src="{{ section.settings.background_image | image_url: 'large' }}">

Sizes: thumb, small, medium, large, hero


Link with text, URL, and optional target.

{
"type": "link",
"id": "button",
"label": "Button",
"with_text": true
}

Usage -- Access properties directly:

<a href="{{ section.settings.button.href }}"
target="{{ section.settings.button.target }}">
{{ section.settings.button.text }}
</a>
PropertyDescription
.textLink display text
.hrefURL (also available as .url)
.target"" or "_blank" for new tab

select

Dropdown selection.

{
"type": "select",
"id": "columns",
"label": "Columns",
"options": [
{"value": "2", "label": "2 Columns"},
{"value": "3", "label": "3 Columns"},
{"value": "4", "label": "4 Columns"}
]
}

number

Numeric input with optional unit.

{
"type": "number",
"id": "count",
"label": "Number of Items"
}

With unit (for CSS variables):

{
"type": "number",
"id": "border_width",
"label": "Border Width",
"unit": "px"
}

range

Slider input with min/max bounds.

{
"type": "range",
"id": "spacing",
"label": "Spacing",
"min": 0,
"max": 100,
"step": 5,
"unit": "px"
}
OptionDescription
minMinimum value (required)
maxMaximum value (required)
stepIncrement amount
unitUnit for display AND CSS variable generation

Allowed units: px, %, em, rem, vh, vw, vmin, vmax, ch, ex

CSS Variable Generation

The unit property is appended to auto-generated CSS variables:

/* With "unit": "px" */
--section-spacing: 20px;

/* Without unit */
--section-opacity: 80;

If the setting controls CSS spacing/sizing, always include unit. Without it, padding: var(--section-spacing) fails because padding: 20 is invalid CSS.


icon

Icon picker with search (uses Remix Icons).

{
"type": "icon",
"id": "icon",
"label": "Icon"
}

Stores the icon class (e.g., ri-star-line). The picker supports search and allows custom class input.

Usage:

<i class="{{ section.settings.icon }}"></i>

checkbox

Boolean toggle.

{
"type": "checkbox",
"id": "show_date",
"label": "Show Date"
}

Usage -- Use natural boolean checks:

{% if section.settings.show_date %}
<span>{{ post.date }}</span>
{% endif %}

Content Pickers

Async search pickers that store a slug. The selected content is available as a Liquid drop in templates.

{
"type": "post",
"id": "featured_post",
"label": "Featured Post",
"placeholder": "Select a post..."
}

Available picker types: post, collection, tag, blog

In presets, use "random" to auto-select a random record:

"presets": [{
"name": "Default",
"settings": {
"featured_post": "random"
}
}]

Conditional Display (show_if)

Show/hide settings based on other values:

{
"type": "checkbox",
"id": "custom_colors",
"label": "Custom Colors"
},
{
"type": "color_alpha",
"id": "bgcolor",
"label": "Background Color",
"show_if": { "setting": "custom_colors", "eq": true }
}

The color picker only appears when the checkbox is checked.


Complete Section Example

A real section schema showing settings, conditional display, and presets:

{% schema %}
{
"name": "Content and Image",
"category": "cta",
"settings": [
{
"type": "header",
"content": "Colors"
},
{
"type": "checkbox",
"id": "custom_colors",
"label": "Custom Colors",
"info": "Override theme colors for this section"
},
{
"type": "color_alpha",
"id": "bgcolor",
"label": "Background Color",
"show_if": { "setting": "custom_colors", "eq": true }
},
{
"type": "color_alpha",
"id": "text_color",
"label": "Text Color",
"show_if": { "setting": "custom_colors", "eq": true }
},
{
"type": "header",
"content": "Content"
},
{
"type": "text",
"id": "title",
"label": "Title",
"nb_rows": 3
},
{
"type": "text",
"id": "body",
"label": "Body",
"html": true,
"nb_rows": 5
},
{
"type": "image",
"id": "image",
"label": "Image"
},
{
"type": "link",
"id": "button",
"label": "Button",
"with_text": true
}
],
"blocks": [],
"presets": [
{
"name": "Content and Image",
"settings": {
"custom_colors": false,
"bgcolor": "",
"text_color": "",
"title": "Lorem ipsum dolor sit amet",
"body": "Consectetur adipiscing elit. Quam a scelerisque amet.",
"image": "https://images.unsplash.com/photo-1551434678-e076c223a692?w=800",
"button": {
"text": "Get Started Today",
"href": "#"
}
}
}
]
}
{% endschema %}

Notice: no "default" on any setting. Every initial value is in the preset. Empty strings ("") for color settings mean "use the theme default."


Quick Reference

TypeLive PreviewKey Usage
headerN/ADisplay-only, organizes settings
infoN/ADisplay-only, explanatory text
text.attr accessor{{ setting.attr }}
colorCSS variabledata-css-vars attribute
color_alphaCSS variablecolor_alpha_to_rgba filter
imageCSS variableimage_url filter
linkN/A.href, .text, .target
selectServer re-renderDirect value access
numberServer re-renderDirect value access
rangeServer re-renderDirect value access, with min/max/step
iconServer re-renderStores icon class (e.g., ri-star-line)
checkboxServer re-renderNatural boolean checks (if/unless)
post, collection, tag, blogServer re-renderStores slug, supports "random" in presets