Skip to main content

Overview

Horizon follows Shopify’s theme architecture with enhanced organization and modern patterns. Understanding this structure is essential for effective theme development.
source/
├── assets/          # 100+ CSS, JS, and static files
├── blocks/          # 94 theme blocks
├── config/          # settings_schema.json and settings_data.json
├── layout/          # theme.liquid and password.liquid
├── locales/         # Translation files (en.default.json, etc.)
├── sections/        # 41 section files (.liquid and .json)
├── snippets/        # 93 reusable Liquid snippets
└── templates/       # 14 JSON template files

Sections

Sections are the primary building blocks of Shopify pages. Horizon includes 41 sections organized by purpose.

Universal Sections

_blocks.liquid - The Foundation

The _blocks.liquid section is Horizon’s most flexible container:
sections/_blocks.liquid
{% capture children %}
  {% content_for 'blocks' %}
{% endcapture %}

{% render 'section', section: section, children: children %}

{% schema %}
{
  "name": "t:names.section",
  "class": "section-wrapper",
  "blocks": [
    { "type": "@theme" },    // Accept any theme block
    { "type": "@app" },      // Accept app blocks
    { "type": "_divider" }   // Built-in divider
  ],
  "settings": [
    {
      "type": "select",
      "id": "content_direction",
      "options": [
        { "value": "column", "label": "t:options.vertical" },
        { "value": "row", "label": "t:options.horizontal" }
      ]
    },
    {
      "type": "select",
      "id": "section_width",
      "options": [
        { "value": "page-width", "label": "t:options.page" },
        { "value": "full-width", "label": "t:options.full" }
      ]
    },
    {
      "type": "select",
      "id": "section_height",
      "options": [
        { "value": "", "label": "t:options.auto" },
        { "value": "small", "label": "t:options.small" },
        { "value": "medium", "label": "t:options.medium" },
        { "value": "large", "label": "t:options.large" },
        { "value": "full-screen", "label": "t:options.full_screen" }
      ]
    }
  ]
}
{% endschema %}
The { "type": "@theme" } block type allows any theme block to be added, making this section universally flexible.

Layout Sections

The hero section supports dual media (images/videos), custom layouts, and flexible content positioning:
{% liquid
  assign media_count = 0
  assign media_1 = 'none'
  assign media_2 = 'none'
  
  if section.settings.image_1 != blank and section.settings.media_type_1 == 'image'
    assign media_1 = 'image'
    assign media_count = media_count | plus: 1
  endif
  
  if section.settings.video_1 != blank and section.settings.media_type_1 == 'video'
    assign media_1 = 'video'
    assign media_count = media_count | plus: 1
  endif
%}
Key Features:
  • Dual media slots (desktop + mobile)
  • Blurred reflection effects
  • Custom height options
  • Background overlays with gradients
Features the advanced bento grid layout system for visually dynamic collection displays.

Page-Specific Sections

  • main-product.liquid - Main product page section
  • featured-product.liquid - Featured product showcase
  • featured-product-information.liquid - Product details
Section groups enable modular header/footer architecture:
sections/header-group.json
{
  "type": "header",
  "name": "t:names.header",
  "sections": {
    "header_announcements": {
      "type": "header-announcements",
      "blocks": {
        "announcement": {
          "type": "_announcement",
          "settings": {
            "text": "Welcome to our store",
            "font_size": "0.75rem"
          }
        }
      }
    },
    "header_section": {
      "type": "header",
      "blocks": {
        "header-logo": { "type": "_header-logo", "static": true },
        "header-menu": { "type": "_header-menu", "static": true }
      },
      "settings": {
        "logo_position": "left",
        "menu_position": "left",
        "enable_sticky_header": "always",
        "enable_transparent_header_home": false
      }
    }
  },
  "order": ["header_announcements", "header_section"]
}

Blocks

Theme blocks (94 total) are prefixed with _ and provide reusable components.

Block Categories

Content Blocks

  • _heading.liquid - Customizable headings
  • _content.liquid - Nested content groups
  • _divider.liquid - Section dividers
  • _inline-text.liquid - Inline typography

Media Blocks

  • _image.liquid - Responsive images
  • _media.liquid - Video/image media
  • _carousel-content.liquid - Carousel items
  • _layered-slide.liquid - Layered slideshows

Product Blocks

  • _product-card.liquid - Product cards
  • _product-card-gallery.liquid - Product images
  • _featured-product.liquid - Featured products
  • _featured-product-price.liquid - Pricing display

Navigation Blocks

  • _header-logo.liquid - Site logo
  • _header-menu.liquid - Navigation menus
  • _footer-social-icons.liquid - Social links
  • _announcement.liquid - Announcements

Block Schema Example

blocks/_content.liquid
{% capture children %}
  {% content_for 'blocks' %}
{% endcapture %}

{% render 'group', children: children, settings: block.settings, shopify_attributes: block.shopify_attributes %}

{% schema %}
{
  "name": "t:names.content",
  "tag": null,
  "blocks": [
    { "type": "@theme" },
    { "type": "@app" },
    { "type": "_divider" }
  ],
  "settings": [
    {
      "type": "select",
      "id": "horizontal_alignment_flex_direction_column",
      "label": "t:settings.alignment",
      "options": [
        { "value": "flex-start", "label": "t:options.left" },
        { "value": "center", "label": "t:options.center" },
        { "value": "flex-end", "label": "t:options.right" }
      ]
    },
    {
      "type": "range",
      "id": "gap",
      "label": "t:settings.gap",
      "min": 0,
      "max": 100,
      "default": 24
    },
    {
      "type": "checkbox",
      "id": "inherit_color_scheme",
      "label": "t:settings.inherit_color_scheme",
      "default": true
    }
  ]
}
{% endschema %}
The _content block is nestable - it accepts other theme blocks, enabling complex layouts through composition.

Snippets

Horizon contains 93 snippets organized by functionality.

Core Snippets

snippets/section.liquid
{%- doc -%}
  Renders a wrapper section

  @param {section} section - The section object
  @param {string} children - The children of the section
{%- enddoc -%}

<div class="section-background color-{{ section.settings.color_scheme }}"></div>
<div
  class="section section--{{ section.settings.section_width }}"
  style="
    {% if section.settings.section_height == 'custom' %}
      --section-min-height: {{ section.settings.section_height_custom }}svh;
    {% elsif section.settings.section_height == 'full-screen' %}
      --section-min-height: 100svh;
    {% endif %}
  "
>
  <div class="custom-section-background">
    {% render 'background-media',
      background_media: section.settings.background_media,
      background_video: section.settings.video,
      background_image: section.settings.background_image
    %}
  </div>

  <div class="border-style custom-section-content">
    {% if section.settings.toggle_overlay %}
      {% render 'overlay', settings: section.settings %}
    {% endif %}

    {{ children }}
  </div>
</div>
Responsibilities:
  • Color scheme application
  • Background media rendering
  • Overlay effects
  • Height and width management
snippets/group.liquid
{%- doc -%}
  Renders block content for all blocks that extend the group block.

  @param {string} children - The DOM content of the group block.
  @param {object} settings - The settings of the group block.
  @param {string} shopify_attributes - String with Shopify attributes.
{%- enddoc -%}

<div
  class="group-block {% if settings.inherit_color_scheme == false %}color-{{ settings.color_scheme }}{% endif %}"
  style="
    {% render 'border-override', settings: settings %}
    {% render 'spacing-style', settings: settings %}
  "
  {{ shopify_attributes }}
>
  {%- if settings.link != blank -%}
    <a href="{{ settings.link }}" class="group-block__link"></a>
  {%- endif -%}

  <div class="group-block__media-wrapper">
    {% render 'background-media',
      background_media: settings.background_media,
      background_video: settings.video,
      background_image: settings.background_image
    %}
  </div>

  {{ children }}
</div>
Renders items in a sophisticated bento box grid:
snippets/bento-grid.liquid
{%- doc -%}
  Takes an array of HTML strings and positions them in a bento box grid.
  Bento boxes can hold up to 12 items.

  @param {string[]} items - Array of HTML strings
{%- enddoc -%}

{% liquid
  assign odd_item_check = items.size | modulo: 12
  if odd_item_check == 1
    assign first_box_size = 11
  else
    assign first_box_size = 12
  endif
%}

{% for item in items %}
  {% if forloop.first or item_modulo == 1 %}
    <div class="bento-box bento-box--items-{{ box_item_count }}">
  {% endif %}

  <div class="bento-box__item">
    {{ item }}
  </div>

  {% if forloop.last or item_modulo == 0 %}
    </div>
  {% endif %}
{% endfor %}

{% stylesheet %}
  .bento-box {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    grid-template-areas:
      'A A A B B B B B B C C C'
      'D D D D D D E E E F F F'
      'G G G H H H I I I I I I'
      'J J J J K K K K L L L L';
  }
{% endstylesheet %}
The bento grid dynamically adjusts for 1-12 items with optimized layouts.

Utility Snippets

  • card-gallery.liquid - Product image galleries
  • collection-card.liquid - Collection cards
  • editorial-product-grid.liquid - Editorial layouts
  • add-to-cart-button.liquid - Add to cart functionality

Templates

Horizon uses JSON templates exclusively (14 files).

Template Structure

templates/product.json
{
  "sections": {
    "main": {
      "type": "main-product",
      "blocks": {
        "vendor": { "type": "text" },
        "title": { "type": "title" },
        "price": { "type": "price" },
        "variant_picker": { "type": "variant_picker" },
        "quantity_selector": { "type": "quantity_selector" },
        "buy_buttons": { "type": "buy_buttons" }
      },
      "block_order": ["vendor", "title", "price", "variant_picker", "quantity_selector", "buy_buttons"]
    }
  },
  "order": ["main"]
}

Available Templates

404.json

Error page template

article.json

Blog post template

blog.json

Blog listing template

cart.json

Shopping cart template

collection.json

Collection template

gift_card.liquid

Gift card (Liquid)

index.json

Homepage template

list-collections.json

All collections template

page.json

Default page template

page.contact.json

Contact page template

password.json

Password page template

product.json

Product template

search.json

Search results template
Only gift_card.liquid uses the Liquid format; all others are JSON for maximum flexibility.

Layout Files

theme.liquid

The main layout file provides the HTML shell:
layout/theme.liquid
<!doctype html>
<html lang="{{ request.locale.iso_code }}">
  <head>
    {%- render 'meta-tags' -%}
    {%- render 'stylesheets' -%}
    {%- render 'fonts' -%}
    {%- render 'scripts' -%}
    {%- render 'theme-styles-variables' -%}
    {%- render 'color-schemes' -%}
    {{ content_for_header }}
  </head>

  <body class="page-width-{{ settings.page_width }}">
    <div id="header-group">
      {% sections 'header-group' %}
    </div>

    <main id="MainContent" role="main">
      {{ content_for_layout }}
    </main>

    <footer>
      {% sections 'footer-group' %}
    </footer>

    {% render 'search-modal' %}
    {% if settings.quick_add %}
      {% render 'quick-add-modal' %}
    {% endif %}
  </body>
</html>

password.liquid

Special layout for password-protected stores.

Assets

Horizon includes 100+ asset files:
  • base.css - Core styles, CSS custom properties
  • Component-specific styles in sections/snippets
  • Scoped styles using {% stylesheet %} tags

Best Practices

Theme blocks are more flexible and reusable. Prefer composing layouts with blocks rather than creating monolithic sections.
Extract common patterns into snippets. Use the {%- doc -%} tag to document parameters.
  • Sections: descriptive names (hero.liquid, main-product.liquid)
  • Blocks: underscore prefix (_heading.liquid, _content.liquid)
  • Snippets: functionality-based names (section.liquid, bento-grid.liquid)
JSON templates provide better flexibility and enable merchants to customize layouts without code.

Next Steps

Liquid Storefronts

Learn about modern Liquid features

Theme Blocks

Deep dive into theme blocks

Development Guide

Set up your development environment

Component Reference

Browse all sections and blocks

Build docs developers (and LLMs) love