Sections, Blocks, and Schema Design Beginner 12 min read

Section Anatomy: Markup, Schema, and Settings

Understand the three essential parts of every Shopify section: the Liquid markup, the schema definition, and how to access settings in your code.

Sections are the building blocks of modern Shopify themes. They combine HTML markup, Liquid logic, and a configuration schema that lets merchants customize content through the theme editor. Understanding how these three parts work together is essential for building flexible, maintainable themes.

🛠 Try the Schema Builder: Don’t want to write JSON by hand? Our Schema Builder lets you visually create section schemas with real-time preview, validation, and support for all setting types.

The Three Parts of a Section

Every section file contains three main parts:

  1. Liquid Markup: The HTML and Liquid code that renders the section
  2. Schema: A JSON configuration that defines settings and capabilities
  3. Settings Access: Using section.settings to make content dynamic
{# sections/example.liquid #}
{# Part 1: Liquid Markup #}
<section class="example-section">
<h2>{{ section.settings.heading }}</h2>
<p>{{ section.settings.text }}</p>
</section>
{# Part 2: Schema #}
{% schema %}
{
"name": "Example Section",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Welcome"
},
{
"type": "textarea",
"id": "text",
"label": "Text content"
}
]
}
{% endschema %}

Part 1: The Liquid Markup

The markup section contains your HTML structure mixed with Liquid code. This is what actually renders on the page.

Basic Structure

<section class="featured-collection">
<div class="container">
<h2 class="section-heading">
{{ section.settings.heading }}
</h2>
<div class="product-grid">
{%- for product in section.settings.collection.products limit: section.settings.limit -%}
{% render 'product-card', product: product %}
{%- endfor -%}
</div>
</div>
</section>

Using CSS Classes from Settings

<section class="hero-banner hero-banner--{{ section.settings.height }}">
<div class="hero-banner__content hero-banner__content--{{ section.settings.text_alignment }}">
{{ section.settings.heading }}
</div>
</section>

Inline Styles from Settings

<section
class="image-banner"
style="
--banner-height: {{ section.settings.height }}px;
--text-color: {{ section.settings.text_color }};
--overlay-opacity: {{ section.settings.overlay_opacity | divided_by: 100.0 }};
"
>

Part 2: The Schema

The schema is a JSON object wrapped in {% schema %} tags. It defines everything about your section’s configuration.

Required Schema Properties

At minimum, every schema needs a name:

{% schema %}
{
"name": "My Section"
}
{% endschema %}

Common Schema Properties

{% schema %}
{
"name": "Featured Collection",
"tag": "section",
"class": "featured-collection-section",
"limit": 1,
"settings": [],
"blocks": [],
"max_blocks": 16,
"presets": [],
"default": {},
"enabled_on": {},
"disabled_on": {}
}
{% endschema %}
PropertyPurpose
nameDisplay name in theme editor
tagHTML wrapper tag (default: div)
classCSS class added to wrapper
limitMax instances per page
settingsArray of setting definitions
blocksArray of block type definitions
max_blocksMaximum blocks allowed
presetsMakes section available in “Add section”
defaultDefault configuration
enabled_onWhere section can be added
disabled_onWhere section cannot be added

The Settings Array

Settings define the customization options merchants see:

{% schema %}
{
"name": "Banner",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Welcome to our store"
},
{
"type": "image_picker",
"id": "image",
"label": "Background image"
},
{
"type": "select",
"id": "height",
"label": "Banner height",
"options": [
{ "value": "small", "label": "Small" },
{ "value": "medium", "label": "Medium" },
{ "value": "large", "label": "Large" }
],
"default": "medium"
},
{
"type": "range",
"id": "overlay_opacity",
"label": "Overlay opacity",
"min": 0,
"max": 100,
"step": 10,
"default": 40,
"unit": "%"
}
]
}
{% endschema %}

Part 3: Accessing Settings

Use section.settings to access the values merchants configure:

{# Text settings #}
{{ section.settings.heading }}
{{ section.settings.button_text }}
{# Boolean settings #}
{% if section.settings.show_vendor %}
<p>{{ product.vendor }}</p>
{% endif %}
{# Number settings #}
{% for product in collection.products limit: section.settings.products_to_show %}
{# Resource settings #}
{% for product in section.settings.collection.products %}
{{ section.settings.image | image_url: width: 800 }}
{# Color settings #}
style="color: {{ section.settings.text_color }};"

The section Object

Beyond settings, the section object provides useful properties:

{{ section.id }} {# Unique ID for this section instance #}
{{ section.settings }} {# All section settings #}
{{ section.blocks }} {# Array of blocks #}
{{ section.blocks.size }} {# Number of blocks #}
{{ section.index }} {# Section position (1-based) #}

Using section.id for Scoped Styles

The section.id is unique per section instance, perfect for scoped CSS:

<style>
#shopify-section-{{ section.id }} .heading {
color: {{ section.settings.heading_color }};
font-size: {{ section.settings.heading_size }}px;
}
#shopify-section-{{ section.id }} .content {
background: {{ section.settings.background_color }};
}
</style>
<section class="my-section">
<h2 class="heading">{{ section.settings.heading }}</h2>
<div class="content">{{ section.settings.content }}</div>
</section>

Section Wrapper

Shopify automatically wraps your section in a <div> with specific attributes:

<div id="shopify-section-[id]" class="shopify-section [your-class]">
<!-- Your section content -->
</div>

Customizing the Wrapper

Use tag and class in your schema:

{% schema %}
{
"name": "Hero Banner",
"tag": "section",
"class": "hero-banner-wrapper"
}
{% endschema %}

Output:

<section id="shopify-section-[id]" class="shopify-section hero-banner-wrapper">
<!-- Content -->
</section>

Complete Section Example

Here’s a fully-featured “Featured Collection” section:

{# sections/featured-collection.liquid #}
{%- liquid
assign collection = section.settings.collection
assign limit = section.settings.products_to_show
assign columns = section.settings.columns
-%}
<section class="featured-collection">
<div class="container">
{%- if section.settings.heading != blank -%}
<h2 class="featured-collection__heading">
{{ section.settings.heading }}
</h2>
{%- endif -%}
{%- if section.settings.description != blank -%}
<div class="featured-collection__description">
{{ section.settings.description }}
</div>
{%- endif -%}
{%- if collection != blank -%}
<div class="product-grid product-grid--{{ columns }}-col">
{%- for product in collection.products limit: limit -%}
<div class="product-grid__item">
{% render 'product-card',
product: product,
show_vendor: section.settings.show_vendor
%}
</div>
{%- endfor -%}
</div>
{%- if section.settings.show_view_all -%}
<div class="featured-collection__footer">
<a href="{{ collection.url }}" class="button">
{{ section.settings.view_all_text | default: 'View all' }}
</a>
</div>
{%- endif -%}
{%- else -%}
{%- if request.design_mode -%}
<div class="placeholder-message">
<p>Select a collection to display products.</p>
</div>
{%- endif -%}
{%- endif -%}
</div>
</section>
<style>
#shopify-section-{{ section.id }} {
padding-top: {{ section.settings.padding_top }}px;
padding-bottom: {{ section.settings.padding_bottom }}px;
background-color: {{ section.settings.background_color }};
}
#shopify-section-{{ section.id }} .featured-collection__heading {
color: {{ section.settings.heading_color }};
}
</style>
{% schema %}
{
"name": "Featured Collection",
"tag": "section",
"class": "section-featured-collection",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading",
"default": "Featured Products"
},
{
"type": "richtext",
"id": "description",
"label": "Description"
},
{
"type": "collection",
"id": "collection",
"label": "Collection"
},
{
"type": "range",
"id": "products_to_show",
"label": "Products to show",
"min": 2,
"max": 12,
"step": 1,
"default": 4
},
{
"type": "select",
"id": "columns",
"label": "Columns",
"options": [
{ "value": "2", "label": "2" },
{ "value": "3", "label": "3" },
{ "value": "4", "label": "4" }
],
"default": "4"
},
{
"type": "checkbox",
"id": "show_vendor",
"label": "Show vendor",
"default": false
},
{
"type": "checkbox",
"id": "show_view_all",
"label": "Show 'View all' button",
"default": true
},
{
"type": "text",
"id": "view_all_text",
"label": "'View all' button text",
"default": "View all"
},
{
"type": "header",
"content": "Colors"
},
{
"type": "color",
"id": "background_color",
"label": "Background color",
"default": "#ffffff"
},
{
"type": "color",
"id": "heading_color",
"label": "Heading color",
"default": "#000000"
},
{
"type": "header",
"content": "Spacing"
},
{
"type": "range",
"id": "padding_top",
"label": "Padding top",
"min": 0,
"max": 100,
"step": 4,
"default": 40,
"unit": "px"
},
{
"type": "range",
"id": "padding_bottom",
"label": "Padding bottom",
"min": 0,
"max": 100,
"step": 4,
"default": 40,
"unit": "px"
}
],
"presets": [
{
"name": "Featured Collection"
}
]
}
{% endschema %}

Design Mode Detection

Show helpful messages when merchants are editing:

{%- if collection == blank -%}
{%- if request.design_mode -%}
<div class="placeholder">
<p>Select a collection in the section settings.</p>
</div>
{%- endif -%}
{%- endif -%}

Practice Exercise

Create a simple “Text with Image” section that has:

  1. A heading
  2. Text content (richtext)
  3. An image picker
  4. A setting to flip the layout (image left/right)
<section class="text-with-image text-with-image--{{ section.settings.layout }}">
<div class="text-with-image__content">
{%- if section.settings.heading != blank -%}
<h2>{{ section.settings.heading }}</h2>
{%- endif -%}
{%- if section.settings.text != blank -%}
<div class="rte">{{ section.settings.text }}</div>
{%- endif -%}
</div>
<div class="text-with-image__media">
{%- if section.settings.image != blank -%}
{{ section.settings.image | image_url: width: 800 | image_tag: loading: 'lazy' }}
{%- else -%}
{{ 'image' | placeholder_svg_tag: 'placeholder' }}
{%- endif -%}
</div>
</section>
{% schema %}
{
"name": "Text with Image",
"settings": [
{
"type": "text",
"id": "heading",
"label": "Heading"
},
{
"type": "richtext",
"id": "text",
"label": "Text"
},
{
"type": "image_picker",
"id": "image",
"label": "Image"
},
{
"type": "select",
"id": "layout",
"label": "Layout",
"options": [
{ "value": "image-left", "label": "Image left" },
{ "value": "image-right", "label": "Image right" }
],
"default": "image-left"
}
],
"presets": [
{
"name": "Text with Image"
}
]
}
{% endschema %}

Key Takeaways

  1. Sections have three parts: markup, schema, and settings access
  2. Schema defines the section’s name, settings, blocks, and capabilities
  3. section.settings accesses merchant-configured values
  4. section.id provides a unique identifier for scoped styles
  5. Shopify wraps sections in a div with shopify-section class
  6. Use request.design_mode to show helpful placeholders in the editor

What’s Next?

Now that you understand section basics, the next lesson covers Blocks for creating repeatable, reorderable content within your sections.

Finished this lesson?

Mark it complete to track your progress.

Discussion

Loading comments...