Skip to main content

Live Preview

How the admin editor provides instant preview of changes.

Overview

When editing section settings in the admin, changes appear instantly in the preview iframe. The system uses two update paths based on setting type:

  1. CSS hot-reload - For colors, fonts (save + reload section CSS)
  2. HTML re-render - For text and structural changes (server renders full section HTML)

Both paths are server-side. The difference is efficiency - CSS hot-reload only fetches new CSS, while HTML re-render fetches the entire section.

Update Paths

Path 1: CSS Hot-Reload

For CSS-relevant settings (color, color_alpha, font):

  1. Settings auto-save to database (150ms debounce)
  2. Server regenerates section CSS from .css.liquid template
  3. CSS link tag in iframe refreshes with cache-busting timestamp
  4. Visual update applies without touching HTML

Path 2: HTML Re-render

For content settings (text, textarea, link, etc.) and structural settings (select, checkbox, number):

  1. Settings sent to preview endpoint (300ms debounce)
  2. Server renders complete section HTML with temporary values
  3. JavaScript replaces the section in iframe via postMessage
  4. Settings auto-save (500ms debounce)

Setting Type Categories

// CSS-only: Save + CSS hot-reload (fastest)
const CSS_ONLY_TYPES = ["color", "color_alpha", "font"]

// HTML-only: Server re-render (fast)
const HTML_ONLY_TYPES = ["text", "textarea", "collection", "post", "tag", "link", "url", "header", "info", "icon"]

// Ambiguous: Do BOTH CSS + HTML (safe fallback)
// range, number, select, checkbox, image

CSS Variables

For colors and images, use CSS variables with the data-css-vars attribute:

{% capture section_style %}
--bgcolor: {{ section.settings.bgcolor }};
--overlay: {{ section.settings.overlay | color_alpha_to_rgba }};
--bg-image: url('{{ section.settings.image | image_url: 'hero' }}');
{% endcapture %}

{% section_wrapper 'section' style: section_style data-css-vars: 'bgcolor,overlay,image' %}
<div style="background: var(--overlay), var(--bg-image); background-color: var(--bgcolor);">
...
</div>
{% endsection_wrapper %}

The data-css-vars attribute lists which settings should trigger CSS hot-reload.

The .attr Accessor (Optional)

The .attr accessor outputs data attributes for element identification:

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

Outputs:

<h2 data-setting="title" data-section-id="abc123">My Title</h2>

Note: .attr is NOT required for live preview to work. It's a convenience that:

  • Provides unique identifiers for debugging
  • May be used by future optimizations
  • Helps with CSS targeting via [data-setting="..."]

Live preview works via server re-render regardless of whether .attr is used.

Section ID

Each section has a unique UUID (section.id) provided by section_wrapper:

<section data-section-id="abc123">
<!-- All content inherits this section context -->
</section>

This ID is used to:

  1. Target the correct section for HTML replacement
  2. Scope CSS variables to the section
  3. Trigger CSS hot-reload for the right CSS link tag

Complete Example

{% capture section_style %}
--bgcolor: {{ section.settings.bgcolor }};
--text-color: {{ section.settings.text_color }};
--overlay: {{ section.settings.overlay | color_alpha_to_rgba }};
--bg-image: url('{{ section.settings.image | image_url: 'hero' }}');
{% endcapture %}

{% section_wrapper 'section' class: 'cta' style: section_style data-css-vars: 'bgcolor,text_color,overlay,image' %}
<div class="cta-background" style="background: var(--overlay), var(--bg-image); background-color: var(--bgcolor);">
<div class="cta-content" style="color: var(--text-color);">
{% htmltag 'h2' section.settings.title class: 'cta-title' %}
{% htmltag 'p' section.settings.body class: 'cta-body' %}

{% if section.settings.show_button %}
<a href="{{ section.settings.button | link_href }}" class="btn">
{{ section.settings.button | link_text }}
</a>
{% endif %}
</div>
</div>
{% endsection_wrapper %}

{% schema %}
{
"name": "CTA Section",
"category": "cta",
"settings": [
{
"type": "text",
"id": "title",
"label": "Title",
"default": "Ready to get started?"
},
{
"type": "text",
"id": "body",
"label": "Body",
"nb_rows": 3
},
{
"type": "color",
"id": "bgcolor",
"label": "Background Color",
"default": "#1F2937"
},
{
"type": "color",
"id": "text_color",
"label": "Text Color",
"default": "#FFFFFF"
},
{
"type": "color_alpha",
"id": "overlay",
"label": "Image Overlay",
"default": {"color": "#000000", "alpha": 50}
},
{
"type": "image",
"id": "image",
"label": "Background Image"
},
{
"type": "checkbox",
"id": "show_button",
"label": "Show Button",
"default": true
},
{
"type": "link",
"id": "button",
"label": "Button",
"with_text": true,
"show_if": { "setting": "show_button", "eq": true }
}
]
}
{% endschema %}

What Updates How

Setting TypeUpdate MethodSpeed
colorCSS hot-reload~150ms
color_alphaCSS hot-reload~150ms
fontCSS hot-reload~150ms
textServer re-render~300ms
textareaServer re-render~300ms
linkServer re-render~300ms
selectCSS + HTML (both)~300ms
numberCSS + HTML (both)~300ms
rangeCSS + HTML (both)~300ms
checkboxCSS + HTML (both)~300ms
imageCSS + HTML (both)~300ms

Tips

  1. Use CSS variables for any style-related setting (colors, images)
  2. Use htmltag for text elements - cleaner than manual .attr
  3. Test live preview when developing new sections
  4. Use natural boolean checks for checkbox settings (if, unless)