Knowledge Hub
What blocks solve
Section settings work for fixed content—one heading, one CTA, one background image. Blocks solve repeatable content: FAQ item seven, slide four, feature card twelve. Each block is a row merchants manage independently in the theme editor sidebar.
Block architecture in Liquid
Schema defines block types with names and per-block settings. Liquid loops over section.blocks, reads block.settings, and outputs block.shopify_attributes on wrappers for editor integration.
Block loop pattern
{% for block in section.blocks %}
<div class="row" {{ block.shopify_attributes }}>
{% case block.type %}
{% when 'slide' %}
{{ block.settings.image | image_tag }}
{% when 'faq_item' %}
<h3>{{ block.settings.question }}</h3>
{% endcase %}
</div>
{% endfor %}FAQ blocks
FAQ blocks carry question (text) and answer (richtext) settings. Merchants add rows as support policies change. Convert FAQ HTML with /convert-faq-html-to-liquid or Block mode in /converter.
FAQ block schema
{
"type": "faq_item",
"name": "FAQ item",
"settings": [
{ "type": "text", "id": "question", "label": "Question" },
{ "type": "richtext", "id": "answer", "label": "Answer" }
]
}Slider blocks
Each slide is a block with image_picker, heading, body, and url settings. Section-level settings control autoplay and navigation. See /convert-slider-html-to-liquid for conversion patterns.
Tab blocks
Tab panels use blocks with label and richtext content. Merchants rename tabs and update policy copy without redeploying. /convert-tabs-html-to-liquid covers HTML conversion.
Accordion blocks
Accordion rows extend FAQ blocks with title and richtext content—common on product detail pages for materials and sizing. /convert-accordion-html-to-liquid explains the HTML workflow.
Merchant editing capabilities
- Add block — insert a new row from the sidebar.
- Remove block — delete without code changes.
- Reorder — drag blocks to change sequence.
- Duplicate — copy a configured row as a starting point.
- Per-block settings — edit only the selected row's fields.
Block schema best practices
- Name block types descriptively: slide, faq_item, tab_panel.
- Set max_blocks to prevent runaway row counts.
- Seed presets with two to four starter blocks.
- Use case block.type when one section mixes multiple block types.
- Keep per-block setting counts low for editor clarity.
Generating blocks from HTML
HTML to Liquid Converter detects repeating DOM structures and exports Block mode output with schema and scoped CSS. Pair with /shopify-schema-guide for refinement and /shopify-liquid-examples for Liquid reference patterns.
Presets that teach merchants block behavior
A preset with zero blocks forces merchants to discover Add block on their own—acceptable for power users, painful for first-time editors. Ship two to four seeded blocks with realistic defaults so the storefront preview looks complete on insert. Name presets after use cases—FAQ shipping, Hero slider, Product tabs—not internal ticket numbers. When a section supports multiple block types, create separate presets per layout—FAQ compact versus FAQ with icons—instead of one preset merchants must dismantle.
Preset block settings serialize into template JSON when merchants add the section. Changing preset defaults in code does not retroactively update existing instances—only new inserts pick up new defaults. Document that limitation in client training so merchants are not surprised when old homepage rows do not change after your deploy.
Block limits and editor guardrails
max_blocks in schema is a merchant guardrail, not a performance fix by itself—pair caps with reasonable defaults and editor copy in paragraph settings explaining recommended counts. min_blocks is rarely used but can enforce at least one FAQ row. Block order in the sidebar follows section.blocks array order; drag-and-drop updates template JSON on save. Train merchants that duplicate block is faster than retyping five fields for a new FAQ row that mirrors an existing policy format.
When one block type should not mix with another in the same section—video hero slides beside image-only slides—consider splitting into two section files instead of complex case branches merchants cannot understand. Simpler editor mental models reduce misconfiguration. Document which block types appear in which preset so support can answer tickets without opening the repo. Revisit block caps when clients upgrade to Shopify Plus and add more regional landing pages—what was a safe max_blocks on launch may be tight a year later.
Blocks in plain language
Section settings describe the module as a whole—heading, background color, autoplay toggle. Blocks describe rows inside the module—slide three, FAQ item seven, tab panel two. Each block has a type defined in schema (faq_item, slide, tab_panel) and its own settings object merchants edit when that row is selected. Liquid walks section.blocks in order; drag-and-drop in the editor changes loop sequence without code changes. block.shopify_attributes on the outer DOM node connects the selected row in the sidebar to the correct HTML in the preview iframe. Without it, merchants click a block and the editor highlights nothing—a common false bug report. Blocks are the right tool when row count is unpredictable; settings alone are right when the layout is fixed. /how-shopify-sections-work covers where sections sit in JSON templates; this guide covers what happens inside a block-based section file.
Block loop data flow
{% schema %} defines block types + per-block settings
│
▼
Merchant adds/reorders blocks in editor
│
▼
section.blocks array at render time
│
▼
{% for block in section.blocks %}
block.type → case branch
block.settings → row contentSchema declares possibilities; the blocks array is the live merchant configuration.
Block workflow on agency delivery projects
- 01
Decide block granularity in kickoff
A slider with shared navigation is one section, many slide blocks. A comparison table with mixed icon types might need two block types in one section—icon_row and heading_row—rather than one overloaded block.
- 02
Convert repeating HTML with Block mode in /converter
Identical sibling markup is the signal for blocks. The tool proposes block types and per-row settings; verify it did not treat navigation chrome as blocks.
- 03
Set max_blocks and sensible defaults
Cap slides at twelve, FAQ items at twenty—merchants can still break layout, but limits prevent accidental hundred-row loops. Presets ship with three starter blocks.
- 04
Branch on block.type in Liquid
Use {% case block.type %} when one section mixes slide and video blocks. Keep branches thin; move heavy markup to snippets per block type.
- 05
QA reorder, duplicate, and delete
Merchants will duplicate a configured FAQ row and edit one field—confirm duplicate inherits settings. Delete the middle block and confirm CSS does not depend on nth-child indexes from the mockup.
Block mistakes that pass code review but fail merchants
- Missing block.shopify_attributes on the interactive wrapper—editor UX fails silently.
- Using section.settings inside a block loop for row-specific copy—every row shows the same text.
- One block type with twelve settings—sidebar becomes unscrollable; split block types instead.
- No max_blocks on sliders—merchants add forty slides; Lighthouse scores crater.
- Hardcoded JavaScript tab indexes tied to block position—reorder breaks the UI.
- Empty for loop with no {% else %}—merchants delete all blocks and see a blank gap with no hint.
- Mixing @app blocks and custom blocks without documenting which slots accept apps.
- Renaming block type strings after launch—existing template JSON references old types.
Block schema and Liquid standards we enforce
Name block types in snake_case matching domain language: faq_item not block2. Human names in schema appear in the Add block menu—FAQ item beats Generic row. Limit each block type to four to six settings; move section-level toggles up to settings. Use richtext for answers, text for short labels, image_picker for slide media. Presets should include at least two blocks so merchants see repetition immediately. In Liquid, wrap each block in one semantic element—details for FAQ, li for carousel slides if the JS expects it. Pass block to snippets: {% render 'faq-row', block: block %}. Cross-check block patterns against /shopify-liquid-examples for loop shape, then refine schema in /shopify-schema-guide.
Slider blocks: section settings vs slide blocks
Slider schema split
"settings": [
{ "type": "checkbox", "id": "autoplay", "label": "Autoplay", "default": true },
{ "type": "range", "id": "autoplay_speed", "min": 3, "max": 10, "step": 1, "unit": "s", "label": "Speed" }
],
"blocks": [
{
"type": "slide",
"name": "Slide",
"settings": [
{ "type": "image_picker", "id": "image", "label": "Image" },
{ "type": "text", "id": "heading", "label": "Heading" },
{ "type": "url", "id": "link", "label": "Slide link" }
]
}
],
"max_blocks": 12Autoplay belongs at section level; each slide's media belongs in block settings.
Slider Liquid loop
<div class="slider" data-autoplay="{{ section.settings.autoplay }}">
{%- for block in section.blocks -%}
<div class="slider__slide" {{ block.shopify_attributes }}>
{%- if block.settings.image != blank -%}
{{ block.settings.image | image_url: width: 1200 | image_tag: loading: 'lazy' }}
{%- endif -%}
{%- if block.settings.heading != blank -%}
<h3>{{ block.settings.heading }}</h3>
{%- endif -%}
</div>
{%- else -%}
<p>Add slides in the theme editor.</p>
{%- endfor -%}
</div>data-* hooks connect theme JavaScript without inline onclick handlers merchants cannot edit.
Mixed block types with case
Multi-type block loop
{%- for block in section.blocks -%}
{%- case block.type -%}
{%- when 'heading' -%}
<h2 {{ block.shopify_attributes }}>{{ block.settings.text }}</h2>
{%- when 'text' -%}
<div class="rte" {{ block.shopify_attributes }}>{{ block.settings.body }}</div>
{%- when 'image' -%}
<figure {{ block.shopify_attributes }}>
{{ block.settings.image | image_url: width: 1000 | image_tag }}
</figure>
{%- endcase -%}
{%- endfor -%}Mixed block types power flexible landing modules without separate section files per layout variant.
Tab blocks: labels in blocks, behavior in assets
Tab examples on /shopify-liquid-examples show minimal button plus panel pairs. Production tab sections keep panel content in block.settings.content (richtext) and store the active tab index in JavaScript initialized from data attributes—not hardcoded block index zero in Liquid. Merchants rename tabs by editing block labels; reordering blocks must reorder panels without breaking aria-controls ids. Generate stable ids with block.id: tab-{{ block.id }}.
Accordion blocks on product detail pages
Product detail accordions for materials, sizing, and shipping policies are block-heavy sections merchants update seasonally. Use richtext for policy bodies so legal can add lists and links. Keep accordion headers as text settings for predictable heading levels—h3 inside the disclosure trigger, not richtext headings merchants might set to h1. When one accordion row needs a table, richtext is appropriate; validate table markup in the editor preview because oversized tables break mobile layouts. Cap max_blocks around twelve on PDP accordions; long policy pages belong on dedicated page templates, not infinite accordion stacks.
Accordion block schema excerpt
{
"type": "accordion_row",
"name": "Accordion row",
"settings": [
{ "type": "text", "id": "title", "label": "Row title", "default": "Materials" },
{ "type": "richtext", "id": "content", "label": "Row content" }
]
}Separate title and body settings keep the editor form scannable per row.
When blocks are the wrong abstraction
Not every repeating visual row should be a block. Related products on a PDP are usually a collection setting plus a product loop—not manually curated product blocks—because catalog data should stay live. Logo bars sourced from a metaobject list might belong to metafield-driven Liquid rather than twelve image blocks merchants must re-upload. Blocks shine when non-technical users own copy and order; they hurt when data should be automated. In kickoff, ask who updates the content weekly. Marketing-owned repeating copy is block territory. Catalog-driven grids are setting plus loop territory—see /shopify-liquid-examples for collection patterns.
Coordinating blocks with theme CSS and JavaScript assets
Block loops output HTML; sliders and tabs still need theme assets for motion and focus management. Keep JavaScript selectors scoped to the section root id—#shopify-section-{{ section.id }}—so multiple instances on the same template do not attach event listeners to each other. When merchants duplicate a tab section on long landing pages, scoped JS prevents the top tabs from controlling the bottom section. Load slider scripts only when section.blocks.size exceeds one if your theme supports conditional asset tags. CSS grid templates that use grid-template-areas should not hardcode area names per block index; use a single card class on every block wrapper so reordering does not break layout.
Performance, max_blocks, and editor scalability
Every block renders HTML on each request unless you gate with lazy loading inside the loop. Sliders with fifteen uncompressed PNG slides hurt LCP; cap max_blocks and compress assets at upload. FAQ sections with eighty blocks inflate sidebar height—split into two FAQ sections on long policy pages instead. block.shopify_attributes adds small attribute strings; omitting them does not improve performance—it breaks editing. Schema JSON size matters for editor load; dozens of block types with nested settings slow the sidebar. Prefer two focused sections over one kitchen-sink section with six block types unless merchants genuinely mix them. For maintainability, extract row markup to snippets so the section file stays readable when block types multiply. Theme editor usability drops when block setting labels jargon—question and answer, not field_a and field_b.
- Rendering: max_blocks, lazy media, avoid O(n²) nested loops over blocks.
- Maintainability: snippet per block type; stable block type strings after launch.
- Editor UX: two seeded blocks in presets; empty-state {% else %} on loops.
- Schema organization: section settings for behavior; blocks for content rows only.
Practical summary
Reach for blocks when merchants need variable row counts or reordering—FAQs, sliders, tabs, icon rows, testimonial carousels. Keep section settings for module-level behavior. Convert repeating HTML with Block mode in /converter, validate loops against /shopify-liquid-examples, and tighten schema using /shopify-schema-guide. Register the finished section through /shopify-section-tutorial and test duplicate, delete, and reorder before handoff. Blocks are the scalable half of OS 2.0; paired with solid section architecture from /how-shopify-sections-work, they let merchants run campaigns without reopening your sprint board.
Before closing a block-based ticket, run the merchant simulation: add a row, duplicate it, drag it to the top, delete the original, clear one image field, publish preview. If any step breaks layout or editor highlighting, fix block.shopify_attributes and empty states before merge. Log the max_blocks value in the ticket so support knows the cap is intentional. Blocks feel verbose compared to hardcoded HTML—that verbosity is the product. Merchants pay for independence; developers pay upfront in schema design to buy back support hours later.
Converter Block mode expectations
HTML to Liquid Converter Block mode detects repeating siblings with similar class patterns—it is not magic on asymmetric carousels where slide one includes video and slides two through four are images. Review inferred block types manually. Navigation arrows and dot indicators should remain section settings or static markup outside the block loop unless merchants truly need per-slide controls. After export, diff block settings against this guide's FAQ and slider schema excerpts. Rename block types before the first deploy; renaming after merchants configure rows requires JSON surgery in template files.

