Shopify Section Schema Settings: 13 Input Types with Working Examples

A merchant on Dawn 14.1 messaged me at 2:11 AM on a Friday in February 2026. She had added a “Featured Product” section to her homepage and the dropdown was empty. The schema set the type as product_picker instead of product. Two characters off. The fix took 20 seconds. The admin still rendered an empty dropdown until the cache cleared. The pattern below documents every supported type so the next merchant does not type the wrong one.

TL;DR: Shopify section schema supports 13 input types: text, textarea, number, range, checkbox, select, radio, image_picker, video_url, url, color, color_scheme, font_picker, html, richtext, page, blog, link_list, article, product, product_list, collection, collection_list, and metaobject. Each accepts an id, label, default, and type-specific options. The setting values live on section.settings.<id> in Liquid.

Why this matters for your store:

  • A misnamed type breaks the editor UI silently. Theme Check catches some cases but not all of them.
  • The 13 types map to 13 different merchant workflows. Picking the wrong type costs editors clicks every time they touch the section.
  • Default values cascade to every new instance of the section. Setting good defaults reduces support tickets where a merchant adds a section and the page renders broken.

Text inputs: text, textarea, richtext, html

The four text-family types cover plain strings through formatted body copy. Each renders a different editor control.

{# sections/feature-banner.liquid - schema block #}
{% schema %}
{
  "name": "Feature banner",
  "settings": [
    {
      "type": "text",
      "id": "heading",
      "label": "Heading",
      "default": "Built for the way you actually shop"
    },
    {
      "type": "textarea",
      "id": "subheading",
      "label": "Subheading",
      "default": "Three short lines that explain what the section is about."
    },
    {
      "type": "richtext",
      "id": "body",
      "label": "Body copy",
      "default": "<p>Body copy with <strong>inline emphasis</strong> the merchant can edit.</p>"
    }
  ]
}
{% endschema %}

Use text for headlines and short labels. Use textarea for sentence-level copy. Use richtext when the merchant needs bold, italic, links, or lists inline. Use html only when the merchant pastes embed code (a YouTube iframe, a Calendly snippet). Liquid access pattern: {{ section.settings.heading }}. Rich text and html accept raw markup, so escape if a value will be reused in an attribute.

For broader Liquid mechanics, see my Shopify Liquid development guide and the 10 Shopify Custom Liquid section examples post for the full section-build pattern.

Number and range inputs

number accepts any integer. range adds min, max, and step constraints with a slider UI.

{% schema %}
{
  "settings": [
    {
      "type": "number",
      "id": "padding_top",
      "label": "Padding top (px)",
      "default": 48
    },
    {
      "type": "range",
      "id": "column_count",
      "label": "Columns on desktop",
      "min": 1,
      "max": 5,
      "step": 1,
      "unit": "col",
      "default": 3
    }
  ]
}
{% endschema %}

Use range when the merchant should not type a value outside a known range. The slider also signals the constraint visually. Use number for unbounded integers (delay in milliseconds, item counts above the typical max).

Boolean and select inputs

{% schema %}
{
  "settings": [
    {
      "type": "checkbox",
      "id": "show_vendor",
      "label": "Show vendor name on cards",
      "default": false
    },
    {
      "type": "select",
      "id": "card_style",
      "label": "Card style",
      "options": [
        { "value": "minimal", "label": "Minimal" },
        { "value": "outlined", "label": "Outlined" },
        { "value": "filled", "label": "Filled" }
      ],
      "default": "minimal"
    },
    {
      "type": "radio",
      "id": "alignment",
      "label": "Text alignment",
      "options": [
        { "value": "left", "label": "Left" },
        { "value": "center", "label": "Center" }
      ],
      "default": "left"
    }
  ]
}
{% endschema %}

checkbox returns true or false. select returns one of the listed value strings. radio is the same data shape as select but renders as radio buttons (better when there are 2-4 options the merchant should see at a glance).

In Liquid, conditional logic on these settings is straightforward:

{% if section.settings.show_vendor %}
  <p class="vendor">{{ product.vendor }}</p>
{% endif %}

<div class="card card--{{ section.settings.card_style }} text-{{ section.settings.alignment }}">
  …
</div>

Image, video, and file inputs

{% schema %}
{
  "settings": [
    {
      "type": "image_picker",
      "id": "hero_image",
      "label": "Hero image"
    },
    {
      "type": "video_url",
      "id": "demo_video",
      "label": "Demo video",
      "accept": ["youtube", "vimeo"]
    },
    {
      "type": "url",
      "id": "cta_link",
      "label": "Button URL"
    }
  ]
}
{% endschema %}

image_picker returns an image object the merchant uploads or selects from the library. Pair with image_url and image_tag for the rendering pattern. For the full image_url reference, see my Shopify image_url filter complete reference.

video_url accepts a YouTube or Vimeo URL and returns a video_url object with id, type, and url. url accepts any string the merchant types as a link.

Color inputs

{% schema %}
{
  "settings": [
    {
      "type": "color",
      "id": "background",
      "label": "Background color",
      "default": "#FFFFFF"
    },
    {
      "type": "color_scheme",
      "id": "scheme",
      "label": "Color scheme",
      "default": "scheme-1"
    }
  ]
}
{% endschema %}

color returns a single hex value. Use it for one-off color choices that do not belong to the theme palette.

color_scheme references the theme-level color scheme system (introduced in Dawn 7.0). Each color scheme defines background, text, button, and outline colors as a group. The merchant manages schemes once at the theme level and applies them per section. This is the right pattern for cohesive design.

Reference inputs (product, collection, page, blog, article, metaobject)

The reference family lets the merchant pick existing Shopify resources from the admin without typing IDs.

{% schema %}
{
  "settings": [
    {
      "type": "product",
      "id": "featured_product",
      "label": "Featured product"
    },
    {
      "type": "product_list",
      "id": "featured_products",
      "label": "Featured products",
      "limit": 6
    },
    {
      "type": "collection",
      "id": "featured_collection",
      "label": "Featured collection"
    },
    {
      "type": "page",
      "id": "support_page",
      "label": "Support page"
    },
    {
      "type": "blog",
      "id": "featured_blog",
      "label": "Featured blog"
    },
    {
      "type": "article",
      "id": "featured_article",
      "label": "Featured article"
    }
  ]
}
{% endschema %}

product returns the product object directly. Access .title, .handle, .featured_image without an additional all_products lookup:

{% assign featured = section.settings.featured_product %}
{% if featured != blank %}
  <h2>{{ featured.title }}</h2>
  <a href="{{ featured.url }}">View</a>
{% endif %}

product_list returns an array. limit caps how many products the merchant can pick. Use the same limit: and break patterns you would use on any Liquid loop. See my Shopify Liquid for loop break and continue reference.

Metaobject inputs

{% schema %}
{
  "settings": [
    {
      "type": "metaobject",
      "id": "selected_team_member",
      "label": "Team member",
      "metaobject_type": "team_member"
    }
  ]
}
{% endschema %}

The metaobject type accepts a metaobject_type constraint that limits the picker to entries of one definition. Access in Liquid via section.settings.selected_team_member.fields.name, where the fields match the metaobject definition you set up in Settings > Custom data > Metaobjects.

For the broader decision on when to use metaobjects versus product metafields, see my Shopify metaobjects vs metafields post.

Blocks: schema within schema

Blocks are repeating sub-units inside a section. The schema declares block types; the merchant adds instances.

{# sections/feature-grid.liquid #}
{% schema %}
{
  "name": "Feature grid",
  "settings": [],
  "max_blocks": 6,
  "blocks": [
    {
      "type": "feature",
      "name": "Feature",
      "settings": [
        {
          "type": "image_picker",
          "id": "icon",
          "label": "Icon"
        },
        {
          "type": "text",
          "id": "heading",
          "label": "Heading"
        }
      ]
    }
  ],
  "presets": [
    {
      "name": "Feature grid",
      "blocks": [
        { "type": "feature" },
        { "type": "feature" },
        { "type": "feature" }
      ]
    }
  ]
}
{% endschema %}

{% for block in section.blocks %}
  <div class="feature" {{ block.shopify_attributes }}>
    {% if block.settings.icon != blank %}
      {{ block.settings.icon | image_url: width: 96 | image_tag: alt: block.settings.heading }}
    {% endif %}
    <h3>{{ block.settings.heading }}</h3>
  </div>
{% endfor %}

{{ block.shopify_attributes }} is mandatory inside the block render. It outputs the data attributes Shopify’s theme editor uses to highlight the selected block. Without it, the editor cannot scroll to a block when the merchant clicks it in the sidebar.

How to verify your schema

Three checks, three minutes.

  1. Run shopify theme check. The CLI walks every section’s {% schema %} block and flags malformed JSON, unknown types, and missing required keys. Fix everything Theme Check flags before opening the theme editor.

  2. Open the section in the theme editor. Add the section to a page and confirm every setting renders. A setting that does not render usually means a typo in type: (the product_picker versus product from the hook) or a missing required option (select with no options array).

  3. Save default values and confirm they persist. A merchant adding the section for the first time should see the defaults in place. If a default is missing or wrong, the first impression of the section is broken UI.

The takeaway:

  • The 13 supported types cover every common editor input. If you find yourself wanting a 14th, audit whether the merchant workflow can fit the existing set.
  • Use color_scheme over color when the theme palette already has the right scheme defined. Cohesion beats one-off hex picks.
  • Reference types (product, collection, page) return the object directly. Skip all_products[handle] lookups when you have a picker available.
  • Block schema is the right pattern for repeatable content within one section. Section settings are for one-off choices that apply to the whole section.
  • Run Theme Check on every PR. The schema check costs 2 seconds and catches typos that break the editor silently.

Frequently Asked Questions

What setting types does Shopify section schema support?

Shopify section schema supports 13 input types: text, textarea, number, range, checkbox, select, radio, image_picker, video_url, url, color, color_scheme, font_picker, html, richtext, page, blog, link_list, article, product, product_list, collection, collection_list, and metaobject. Each accepts an `id`, `label`, `default`, and type-specific options. The settings render as the editor controls a merchant uses to configure the section without touching code.

How do I add a product picker to a Shopify section?

Use the `product` type for a single product picker, or `product_list` for multiple. Schema: `{ "type": "product", "id": "featured_product", "label": "Featured product" }`. Access in Liquid via `section.settings.featured_product`, which returns the product object directly. Use `.title`, `.handle`, `.featured_image` and any other product property without an additional lookup. The picker UI surfaces in the theme editor immediately.

What is the difference between text and richtext schema settings?

`text` accepts a plain string with no formatting. The editor renders a single-line input. `textarea` is the multi-line version. `richtext` accepts HTML and renders a WYSIWYG editor in the admin, allowing bold, italic, links, and lists. `html` accepts raw HTML with no editor formatting. Use `text` for headlines, `textarea` for short descriptions, `richtext` for body copy a merchant edits regularly, and `html` for power-user embeds (analytics snippets, custom markup).

Can a Shopify section have nested blocks with their own schema?

Yes. The `blocks` array in section schema defines block types, each with its own `settings` array. A merchant adds, removes, and reorders blocks of these types from the theme editor. Each block instance gets its own settings values. Liquid access: `{% for block in section.blocks %}{{ block.settings.heading }}{% endfor %}`. The `max_blocks` schema property caps how many blocks a section can hold. Use blocks for repeatable content within one section (slides, columns, tabs).

How do I set a default value in a section schema setting?

Add a `default` key alongside `type`, `id`, and `label`. The default value type must match the setting type: a string for `text`, a boolean for `checkbox`, a number for `number` and `range`, a hex string for `color`. Example: `{ "type": "text", "id": "heading", "label": "Heading", "default": "Featured products" }`. Defaults apply to new instances of the section; existing instances keep their stored values.

Book Strategy Call