Theme sections

Themes have a new directory called Sections. Sections are Liquid templates that have access to the same global objects, tags, and filters as other templates.

Variables created outside sections are not available within sections. Likewise, variables created in sections are not available outside sections. If a section includes a snippet, the snippet has access to the variables in the section.

Sections support three new Liquid tags. These new tags are not usable outside of sections:

Static and dynamic sections

Sections can be statically included in a theme's templates (like the header and footer), or they can be dynamically added to the theme's homepage from the theme editor.

When Shopify renders sections, it wraps each section in a <div> element with a unique id attribute:

<div id="shopify-section-[id]" class="shopify-section">
  [output of the section template]
</div>

Static sections

You can include a section in a template file using the section tag. This tag behaves like the include tag for snippets: {% section 'header' %} will include the section located at sections/header.liquid. By explicitly calling a section this way, it is referred to as being static.

A section can be included in multiple templates, but there exists only one instance of that section. When a merchant changes the configuration of a static section in one place, that change will apply to all other places where the section is included. Note that sections cannot include other sections.

Dynamic sections

Sections can be dynamically added to the theme's homepage if they have presets defined in their respective {% schema %} tags. Sections with presets will automatically be accessible in the theme editor. From the theme editor, merchants can configure multiple sections of the same type and reorder their appearance on the homepage.

Unlike static sections, you do not use the {% section %} tag to include dynamic sections in your template files. Shopify will render any sections configured in the theme editor in the content_for_index object that must be included in your theme's index.liquid template.

schema

Sections have a schema defined in the Liquid {% schema %} tag. Like a comment tag, schema does not output its content and Liquid code inside a schema tag is not executed.

Each section can have a single schema tag, and schema tags must contain valid JSON. schema tags can be placed anywhere within a section file but cannot be nested inside another Liquid tag.

You can define the following properties within a section's schema tags:

name

Sections should have a name defined in the section schema:

{% schema %}
  {
    "name": "Slideshow"
  }
{% endschema %}

class

You can specify additional classes for the section <div> in the schema:

{% schema %}
  {
    "name": "Slideshow",
    "class": "slideshow"
  }
{% endschema %}
<div id="shopify-section-[id]" class="shopify-section slideshow">
  [output of the section template]
</div>

settings

Sections have their own settings schema which uses the same format as settings_schema.json:

{% schema %}
  {
    "name": "Slideshow",
    "settings": [
      {
        "id": "title",
        "type": "text",
        "label": "Title",
        "default": "Hello world"
      }
    ]
  }
{% endschema %}

Section setting IDs must be unique across all settings of a section, but they don't have to be unique across all sections. They also won't conflict with settings in settings_schema.json.

Each instance of a section has its own setting values. Statically-included sections only have one instance.

You can access setting values through the section object, for example:

{{ section.settings.title }}

The global settings object (which contains the values of settings defined in settings_schema.json) is available within sections, but you cannot access setting values of sections (for example, section.settings) outside of those sections.

blocks

Sections can define blocks in their schemas. Blocks are containers of settings and content which can be added, removed, and reordered within a section.

A block must have a name and a type. A block's type may be any value set by the theme developer. A block has settings in the same format as settings_schema.json.

{% schema %}
  {
    "blocks": [
      {
        "type": "quote",
        "name": "Quote",
        "settings": [
          {
            "id": "content",
            "type": "text",
            "label": "Quote"
          }
        ]
      }
    ]
  }
{% endschema %}

Block types, names, and setting IDs must be unique across all the blocks in their section, but do not have to be unique across all sections. A block's settings can only be accessed within the section they are defined and are not accessible in other sections or templates.

limit

By default, a merchant can add the same block to a section multiple times. If required, you can set a limit for a block so that it can only be added up to a certain number of times:

{% schema %}
  {
    "blocks": [
      {
        "type": "payment_icons",
        "name": "Payment Icons",
        "limit": 1
      }
    ]
  }
{% endschema %}

max_blocks

There is no limit to how many blocks a merchant can add to a section, but you can specify a maximum number of blocks in the section schema:

{% schema %}
  {
    "name": "Slideshow",
    "max_blocks": 2
  }
{% endschema %}

Example

Max blocks example

presets

Section presets are default configurations of a section. They are not related to the theme styles defined in settings_data.json.

When a section has one or more presets, each preset becomes a dynamic section a merchant can add to their theme homepage if the content_for_index object has been included in index.liquid.

Sections that have presets should not be statically included in the theme's templates. Static sections should instead use default settings.

{% schema %}
  {
    "presets": [
      {
        "category": "Custom Content",
        "name": "Text",
        "settings": {
          "heading": "Hello World"
        },
        "blocks": [
          {
            "type": "text",
            "settings": {
              "content": "Once upon a time..."
            }
          }
        ]
      }
    ]
  }
{% endschema %}

Example

Preset example

Presets must have a name and a category. Section presets and will be grouped by their category in the theme editor.

A preset's settings object contains the values that will be assigned to the section when a merchant adds it to their homepage. The preset's settings schema must be valid according to the section's settings schema.

A preset's blocks contains the blocks that the section will include when a merchant adds it to their theme. The preset's blocks must be valid according to the section's block schema.

default

Sections that are statically included in the theme's templates can define their default configuration in the schema:

{% schema %}
  {
    "default": {
      "settings": {
        "heading": "Hello World"
      },
      "blocks": [
        {
          "type": "text",
          "settings": {
            "content": "Once upon a time..."
          }
        }
      ]
    }
  }
{% endschema %}

The format is the same as section presets, except there is no name or category.

You should only need to use this for sections that are meant to be reused or installed on multiple themes or shops. Statically-included sections that come pre-installed with a theme should have their default configuration defined in settings_data.json.

locales

Sections can use global translations defined in the locales directory. The translate and localize filters work within sections, just as they do in other templates.

Sections can also define their own translations in their schema. You should only need to use this for sections that are meant to be reused or installed on multiple themes or shops.

{% schema %}
  {
    "locales": {
      "en": {
        "title": "Welcome"
      },
      "fr": {
        "title": "Bienvenue"
      }
    }
  }
{% endschema %}

The translations will be in the Sections tab of the language editor.

When you update a translation in the language editor, your translations get saved to the applicable locale file and leave the schema unchanged. Translations inside a section's schema act as default values.

In sections, the translate and localize filters will try to find a translation in the context of the current section, then in the section's schema, then in the global context.

For example, {{ 'title' | t }} inside sections/header.liquid will look up sections.header.title in the locale file, then title in the section's schema, then title in the locale file.

Rendering section blocks

Sections are responsible for rendering their blocks by looping over section.blocks:

{% for block in section.blocks %}
  <div class="grid-item" {{ block.shopify_attributes }}>
    {% case block.type %}
    {% when 'text' %}
      {{ block.settings.content }}
    {% when 'image' %}
      <img src="{{ block.settings.image | img_url }}">
    {% endcase %}
  </div>
{% endfor %}

{{ block.shopify_attributes }} must be added to the container element of each block (or, if the block is a single element, to that element). Shopify's theme editor uses shopify_attributes to properly identify blocks for its JavaScript API.

A value for shopify_attributes is only returned inside the theme editor. Themes should not rely on shopify_attributes in their templates or scripts as no value is returned for the customer-facing site.

JavaScript and CSS

Sections can bundle their own script and style assets using the javascript and stylesheet tags. You should only need to use this for sections that are meant to be reused or installed on multiple themes or shops.

Like the schema tag, javascript and stylesheet tags do not output anything, and any Liquid inside them will not be executed. Each section can have one javascript tag and one stylesheet tag.

You can add Sass support to a stylesheet by using {% stylesheet 'scss' %}.

<div class="slideshow" id="slideshow-{{ section.id }}"></div>

<style>
  #slideshow-{{ section.id }} { … }
</style>

{% javascript %}
  $('.slideshow').slideshow();
{% endjavascript %}

{% stylesheet %}
  .slideshow {
    /* default styles */
  }
{% endstylesheet %}

Bundling scripts and styles

The scripts for all sections are concatenated into a single file by Shopify and injected into content_for_header. The injected <script> is set to load asynchronously with the defer attribute. The javascript tag is wrapped in a self-executing anonymous function and a try/catch, which means that variables get defined inside a closure and runtime exceptions won't affect other sections.

The styles for all sections are also concatenated into a single file by Shopify and injected into content_for_header.

Bundled assets are only injected into content_for_header once for each section (not for each instance of a section). To define instance-specific CSS, use an inline <style> tag. To define instance-specific JavaScript, use data-attributes and have the JavaScript read those attributes for each instance. For example: data-slide-speed="{{ section.settings.speed }}"

Theme editor JavaScript API

When merchants customize sections, the HTML of those sections is dynamically added, removed, or re-rendered directly onto the existing DOM without reloading the entire page.

JavaScript that runs when the page loads will not run again when a section is re-rendered or added to the page. This poses a problem for any custom scripts that would need to be re-run.

Theme authors must also make sure that when a section or block is selected, that section or block is visible and remains visible while it is selected. A slideshow, for example, should slide to the block (slide) that is selected and pause while that block is selected.

To help with this, the editor fires DOM events within the context of the theme page (that is, the preview of the theme) which the theme's JavaScript should listen and react to:

type target detail bubbles cancelable Action Expected
shopify:section:load section {sectionId} yes no A section has been added or re-rendered. Re-execute any JavaScript needed for the section to work and display properly (as if the page had just been loaded).
shopify:section:unload section {sectionId} yes no A section has been deleted or is being re-rendered. Clean up any event listeners, variables, etc., so that nothing breaks when the page is interacted with and no memory leaks occur.
shopify:section:select section {sectionId} yes no User has selected the section in the sidebar. Make sure the section is in view and stays in view while selected (scrolling happens automatically).
shopify:section:deselect section {sectionId} yes no User has deselected the section in the sidebar.
shopify:section:reorder section {sectionId} yes no A section has been reordered.
shopify:block:select block {blockId,sectionId} yes no User has selected the block in the sidebar. Make sure the block is in view and stays in view while selected (scrolling happens automatically).
shopify:block:deselect block {blockId,sectionId} yes no User has deselected the block in the sidebar.

Events are triggered directly on section or block elements. In other words, event.target is the section or block element.

Section events are triggered on the <div> generated by Shopify. Block events are triggered on the elements that have the {{ block.shopify_attributes }}.

Events bubble up like other DOM events, such as click and keydown. This allows your scripts to listen for events using addEventListener or using a JavaScript library like jQuery. More information, like the section ID, is attached in event.detail. If you're using an older version of jQuery, you might have to use event.originalEvent.detail instead.

Want to discuss this page?

Visit the Shopify Community