Linked CSS Variable Presets
Several inputs in the page builder support linked CSS variable presets — instead of hardcoding values like font-size: 32px or border-radius: 8px, the builder inserts CSS variable references. This keeps content in sync with theme settings: when a company changes their heading size, brand color, spacing, or corner radius, all linked values update automatically.
How values are stored: When a linked preset is used in the page builder, the persisted value is the full var() form — for example border-radius: var(--corner_radius_md) or color: var(--color_primary). It is not stored as a bare custom property token like --corner_radius_md alone (that would not be valid in a CSS property value). In theme.liquid you still declare properties as --name: …; the storefront and saved builder content reference them as var(--name).
Linked presets are available in:
- Rich text editor — text size, font family, and color presets
- Corner radius inputs — corner radius presets
- Padding inputs — spacing/padding presets
Table of Contents
How It Works
When a company selects a linked preset in the rich text editor, the output uses CSS variable references wrapped in var():
<span style="font-size: var(--font_size_h1); font-family: var(--font_family_heading); font-weight: bold;"> Welcome to our store </span> <span style="color: var(--color_primary);"> Shop now </span>
If the company unlinks and switches to manual controls, the resolved values are applied directly instead:
<span style="font-size: 32px; font-family: Montserrat; font-weight: bold;"> Welcome to our store </span> <span style="color: #2563eb;"> Shop now </span>
For this to work, your theme needs two things: settings defined in settings_schema.json and CSS variables wired in theme.liquid.
Setup
Step 1: Define Settings in settings_schema.json
The builder looks for settings in specific groups by name. Settings in these groups become available as presets:
| Group Name | What It Powers |
|---|---|
typography | Font size presets in the rich text editor |
color_schema | Color presets in the rich text editor |
corner_radius | Corner radius presets |
padding | Padding/spacing presets |
custom_font_sizes | Additional custom text size presets (optional) |
custom_colors | Additional custom color presets (optional) |
Font family settings (font_family_heading, font_family_body) can be in any group — they are resolved by setting ID, not group name.
Example typography settings:
{ "name": "typography", "settings": [ { "type": "range", "id": "font_size_h1", "label": "Heading 1 Size", "min": 16, "max": 80, "step": 1, "default": 40, "unit": "px" }, { "type": "range", "id": "font_size_h2", "label": "Heading 2 Size", "min": 16, "max": 72, "step": 1, "default": 32, "unit": "px" }, { "type": "font_picker", "id": "font_family_heading", "label": "Heading Font", "default": "Montserrat" }, { "type": "font_picker", "id": "font_family_body", "label": "Body Font", "default": "Inter" } ] }
Example color settings:
{ "name": "color_schema", "settings": [ { "type": "color", "id": "color_primary", "label": "Primary Color", "default": "#2563eb" }, { "type": "color", "id": "color_body", "label": "Body Text Color", "default": "#1a1a2e" } ] }
Step 2: Wire Settings to CSS Variables in theme.liquid
Inside a {%- style -%}...{%- endstyle -%} or <style>...</style> block in layouts/theme.liquid, define CSS custom properties that reference your settings:
{'%' style '%'}
:root {
/* Typography */
--font_size_h1: {{ settings.font_size_h1 | append: 'px' }};
--font_size_h2: {{ settings.font_size_h2 | append: 'px' }};
--font_size_h3: {{ settings.font_size_h3 | append: 'px' }};
--font_family_heading: {{ settings.font_family_heading | font_family }};
--font_family_body: {{ settings.font_family_body | font_family }};
/* Colors */
--color_primary: {{ settings.color_primary }};
--color_body: {{ settings.color_body }};
--color_heading: {{ settings.color_heading }};
/* Corner Radius */
--corner_radius_sm: {{ settings.corner_radius_sm | append: 'px' }};
--corner_radius_md: {{ settings.corner_radius_md | append: 'px' }};
--corner_radius_lg: {{ settings.corner_radius_lg | append: 'px' }};
/* Padding / Spacing */
--spacing_sm: {{ settings.spacing_sm | append: 'px' }};
--spacing_md: {{ settings.spacing_md | append: 'px' }};
--spacing_lg: {{ settings.spacing_lg | append: 'px' }};
}
{'%' endstyle '%'}
If a setting in a recognized group has a matching CSS variable in theme.liquid, the preset becomes linkable in the builder.
Corner Radius Presets
Corner radius inputs support linked CSS variable presets. Define corner radius settings in the corner_radius group and map them to CSS variables in theme.liquid.
settings_schema.json:
{ "name": "corner_radius", "settings": [ { "type": "range", "id": "corner_radius_sm", "label": "Small", "min": 0, "max": 24, "step": 1, "default": 4, "unit": "px" }, { "type": "range", "id": "corner_radius_md", "label": "Medium", "min": 0, "max": 32, "step": 1, "default": 8, "unit": "px" }, { "type": "range", "id": "corner_radius_lg", "label": "Large", "min": 0, "max": 48, "step": 1, "default": 16, "unit": "px" } ] }
When a preset is selected, the saved value is the var() reference (e.g. var(--corner_radius_md)), not the bare name --corner_radius_md. The input shows the preset label in read-only mode. When corners are linked, the preset applies to all four corners.
Padding Presets
Padding inputs support the same linked preset pattern using the padding group name.
settings_schema.json:
{ "name": "padding", "settings": [ { "type": "range", "id": "spacing_sm", "label": "Small", "min": 0, "max": 48, "step": 1, "default": 8, "unit": "px" }, { "type": "range", "id": "spacing_md", "label": "Medium", "min": 0, "max": 64, "step": 1, "default": 16, "unit": "px" }, { "type": "range", "id": "spacing_lg", "label": "Large", "min": 0, "max": 96, "step": 1, "default": 32, "unit": "px" } ] }
When a preset is selected, the saved value uses var(--token) on the selected side(s) (for example padding-top: var(--spacing_md)), not bare --spacing_md. When sides are linked, the preset applies to all four sides.
How the Mapping Works
The admin parses theme.liquid and matches this pattern:
--{css_var_name}: {{ settings.{setting_id} ...
It builds a map of setting_id to css_var_name (the --… name from the left-hand side of the declaration). When the builder saves a linked preset, it writes that token inside var() in the stored style (e.g. mapping color_primary → --color_primary results in color: var(--color_primary) in saved content).
Line in theme.liquid | Detected Mapping |
|---|---|
--font_size_h1: {{ settings.font_size_h1 | append: 'px' }}; | font_size_h1 → --font_size_h1 |
--color_primary: {{ settings.color_primary }}; | color_primary → --color_primary |
--font_family_heading: {{ settings.font_family_heading | font_family }}; | font_family_heading → --font_family_heading |
Naming Convention
The CSS variable name does not need to match the setting ID. All of these work:
--font_size_h1: {{ settings.font_size_h1 | append: 'px' }}; --heading-size-1: {{ settings.font_size_h1 | append: 'px' }}; --h1-size: {{ settings.font_size_h1 | append: 'px' }};
The parser matches on the settings.{id} part, not the variable name. However, keeping names consistent (e.g., --font_size_h1 for settings.font_size_h1) is recommended for clarity.
What Gets Linked and What Doesn't
Not everything becomes a linked preset:
- Custom presets (from
custom_font_sizes/custom_colorsgroups) — these are user-added values that don't map to CSS variables intheme.liquid. They always apply resolved values. - Settings without a CSS variable in
theme.liquid— if a setting exists insettings_schema.jsonbut has no corresponding--var: {{ settings.id }}line intheme.liquid, it will still appear as a preset but will apply the resolved value directly. - Font weight — always applied as a resolved value (
bold/normal), not as a CSS variable. There is no theme setting for font weight.
Default Behavior (Linked Presets)
The toolbar shows two preset pickers: Text Presets and Color Presets. Each preset in the dropdown corresponds to a theme setting. Selecting a preset writes inline styles using var(--setting_token) (always the var() wrapper), matching the rich text, corner radius, and padding behavior above.
Unlinking
Each preset picker has an "Unlink Variables" option in its footer. Clicking it:
- Resolves any active CSS variable values back to their current concrete values
- Switches the toolbar to manual mode showing individual controls: Font Family picker, Font Size picker, and Color picker
The toolbar has a "Link Variables" option to switch back to preset mode.