Skip to content

Shopify sections, blocks, snippets, and LiquidDoc

A Shopify guide for coding agents. Also covers section schema, theme blocks, liquid snippets, liquiddoc, merchant settings.

Use this guide when exposing theme-editor controls or creating reusable Liquid. The schema is a merchant-facing API: settings and block types become persisted data, so identifiers must stay stable after release.

Write one valid schema object

A section or theme block may contain one {% schema %} block whose body is strict JSON. It can define name, tag, class, limit, settings, blocks, presets, default, enabled_on, and disabled_on where Shopify allows them.

  • Give every setting a stable id, supported type, and clear label.
  • Add default, info, placeholder, options, min, max, step, or unit only when supported by that setting type.
  • Group related settings with headers or paragraphs sparingly. Keep the most important controls easy to find.
  • Use translation keys for schema labels when the theme supports multiple editor languages.
  • A preset makes a section or block addable in the theme editor. Do not add a preset when the component should exist only through a fixed template or parent.
  • Use enabled_on or disabled_on to constrain valid templates and section groups instead of hiding invalid placements with Liquid conditions.

Render settings defensively. A merchant can leave text, images, links, products, collections, menus, and metaobject references empty.

Use a CSS custom property when one setting maps to one CSS property, such as gap, alignment, or padding. Use a constrained class value when one setting selects a coordinated group of styles, such as a vertical or horizontal layout. Never interpolate unrestricted merchant text into a class name, selector, declaration name, or executable code.

For a mobile layout choice, expose the few supported options with a select setting instead of accepting an arbitrary number. Keep option value types consistent and make the default one of the declared values.

Support blocks without erasing app extensibility

Section blocks are declared in the section schema and rendered through section.blocks. Each block wrapper should include {{ block.shopify_attributes }} so the theme editor can select and reorder it.

{% for block in section.blocks %}
  <div {{ block.shopify_attributes }}>
    {{ block.settings.text }}
  </div>
{% endfor %}

When a section accepts theme blocks, include the documented @theme type and render {% content_for 'blocks' %}. When it accepts app blocks, preserve the @app entry and render app content as Shopify documents. Never swallow app blocks inside unrelated markup or replace them with copied output.

A directly rendered static theme block uses a stable type and ID:

{% content_for 'block', type: 'text', id: 'intro' %}

Put a LiquidDoc header in that block so its purpose and static rendering example remain available to Shopify tooling.

Make snippets explicit and documented

Use snippets for repeated rendering logic, not merchant configuration. Pass values by name with render. Keep a snippet's output valid when optional inputs are missing.

Add LiquidDoc at the top of new or materially changed snippets. Document the description, every parameter, whether it is required, its expected type, and an example when usage is not obvious.

{% doc %}
  Renders a product price using Shopify money formatting.

  @param {product} product - Product whose selected variant supplies the price.
  @param {boolean} [show_compare_at] - Whether to show a higher compare-at price.

  @example
  {% render 'product-price', product: product, show_compare_at: true %}
{% enddoc %}

Do not copy large objects into captured strings or parse rendered HTML to recover data. Pass the object or scalar the snippet needs.

Keep component assets with the component

Use {% stylesheet %} and {% javascript %} for component CSS and JavaScript in snippets, blocks, and sections. These tags are not general-purpose layout, template, config, locale, or asset-file syntax. Keep only truly global or critical static assets in assets, and load theme assets with Shopify's documented asset filters.

Ensure every selector still matches the emitted ID or class. When several effects need transform, combine them deliberately so one declaration does not erase another. Prefer native HTML behavior and modern browser APIs, and do not add a third-party library for behavior the component can implement safely itself.

Keep markup portable

Use semantic HTML first. Add unique input IDs, matching labels, usable button names, visible focus styles, and aria-* only when native semantics do not express the behavior. Include image alt text and dimensions. Make block and section markup useful without JavaScript; enhance it only when the enhancement has a clear fallback.

Primary Shopify sources

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-shopify-guide({ topic: "shopify-sections-blocks-snippets" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems