# Blocks Learn how to create and customize theme blocks. ## Introduction to Blocks Blocks are modular content elements that can be added to sections in Finqu themes. They allow for flexible and customizable layouts within a section. Most blocks render content directly; some blocks are **layout blocks** that contain child blocks in named containers (nesting is limited to a single level). ## How Blocks Are Rendered Blocks are rendered inside sections using the `container` tag. Each block is defined in the `blocks/` directory and rendered in the order specified by the theme editor or default configuration. You can also render a block statically with the `block` tag: ```liquid {% block 'product-title' %} {% block 'app/part-payment' id: 'product-part-payment' %} ``` ### Inline display For side-by-side block layout (e.g. product card rows), use `display: 'inline'` on the block tag or in the block schema: ```liquid {% block 'product-price', display: 'inline' %} ``` ```json { "name": { "en": "Price" }, "category": "content", "display": "inline" } ``` Inline blocks flow horizontally in the designer instead of stacking vertically. ## Block Directory All block files are stored in the `blocks` directory of your theme. Each file represents a single block and contains its Liquid markup, logic, and schema. ## Block Schema Each block file defines its configuration using a `{% schema %}` tag. The schema describes the block's name, description, tag, class, category, and settings. For example: ```liquid {% schema %} { "name": { "en": "FAQ Item", "fi": "UKK-kohta" }, "description": { "en": "A single question and answer pair." }, "tag": "div", "class": "block block-faq-item", "category": "content", "settings": { // ...block settings... } } {% endschema %} ``` - The `category` property must match one of the categories defined in your theme’s `settings_schema.json` file. ## Block Schema Properties Below is a table describing the main properties available in a block schema, along with explanations and examples for each: | Property | Description | Example | |------------|-----------------------------------------------------------------------------|---------| | `name` | The display name of the block, usually localized for different languages. **Required.** | `{ "en": "FAQ Item", "fi": "UKK-kohta" }` | | `description` | Optional description shown in the editor and used for discovery. | `{ "en": "A single question and answer pair." }` | | `category` | The category for the block, must match a category in [`settings_schema.json`](/build-with-finqu/liquid-themes/settings#theme-settings-settings_schemajson). **Required.** | `"content"` | | `tag` | The HTML tag or identifier for the block. | `"div"` | | `class` | CSS classes applied to the block container. | `"block block-faq-item"` | | `templates` | Template types the block is available on. Empty or absent = all templates. | `["product"]` | | `private` | If `true`, hidden from the general block picker; only addable where whitelisted. Defaults to `false`. | `true` | | `display` | Editor rendering mode for the block wrapper. Currently only `"inline"` is supported. | `"inline"` | | `allowed_blocks` | Optional whitelist on a layout block schema for which child blocks may be added. Container-level `allowed_blocks` take precedence when adding into a specific container. | `["product-title", "product-price"]` | | `settings` | [Configuration options](/build-with-finqu/liquid-themes/settings) for the block, such as text fields, images, etc. | `{ /* ...block settings... */ }` | | `containers` | Declares this block as a layout block with child drop zones. | See [Layout blocks](#layout-blocks-and-containers) | | `containers[].id` | Container id used by `{% container 'id' %}`. **Required.** | `"details"` | | `containers[].title` | Container label in the designer. | `{ "en": "Details" }` | | `containers[].type` | Container type, e.g. `"static"` for a fixed container. | `"static"` | | `containers[].allowed_blocks` | Whitelist of blocks accepted by the container. Empty = all public blocks. | `["product-title", "product-price"]` | | `containers[].preset` | Blocks seeded into this container when a statically imported block/section has no stored configuration. See [Container preset blocks](#container-preset-blocks). | `{ "blocks": ["product-title"] }` | | `presets` | Predefined variants shown in the add-block picker. See [Block presets](#block-presets). | `[{ "name": "Default", "default": true }]` | Each property helps define how the block appears and behaves in the theme editor and on the storefront. For more details on settings, see the relevant documentation sections below. ## Template Scope (`templates`) Both blocks and sections may declare a `templates` array in their `{% schema %}`. The block is then only offered on matching template **types**. ```liquid {% schema %} { "name": { "en": "Part-payment calculator" }, "category": "content", "templates": ["product"] } {% endschema %} ``` - The template **type** is the part before the first dot. For example the templates `product` and `product.custom` both have type `product`. - Template names can also be nested paths, e.g. `"marketing/cart"` — the type-matching rule still applies to whatever precedes the first dot. - An **empty or absent** `templates` array means "available on all templates". - Use this as your **general placement context**. It is coarse and predictable; prefer it over trying to encode fine-grained semantic context. | Use case | `templates` | |----------|-------------| | Product part-payment calculator | `["product"]` | | Cart-level calculator | `["cart"]` | | Generic marketing block | omit (available everywhere) | Section-level `templates` works the same way. See [Sections](/build-with-finqu/liquid-themes/sections#section-creatability-and-placement-flags). ## Layout Blocks and Containers A **layout block** is a block whose schema declares one or more `containers`. Each container is a drop zone that can hold **child blocks**. Nesting is limited to a **single level** — a child block cannot itself contain further blocks. ### Parent (layout) block `blocks/product-card.liquid` ```liquid
Welcome to our store.
" } } ] } ``` | Field | Type | Description | |-------|------|-------------| | `id` | string | Optional stable identifier for this preset variant. | | `name` | string \| localized object | Label shown for this preset in the add-block picker. | | `default` | boolean | If `true`, this is the default preset offered. | | `settings` | object | Setting id → value pairs applied to the block on add. | | `blocks` | array | Nested child block instances for layout blocks. When present, [container presets](#container-preset-blocks) are **not** used — the preset's `blocks` takes over entirely. | Each entry in a preset's `blocks` array uses the same shape as [section preset block instances](/build-with-finqu/liquid-themes/sections#preset-block-instances): `name`, optional `id`, `settings`, `container`, and nested `blocks`. For localized preset copy and locale-keyed preset maps, see [Localization](/build-with-finqu/liquid-themes/localization#presets). ## Private Blocks (`private`) Set `private: true` on a block to **remove it from the general block picker**. A private block can only be added where it is **explicitly listed** in an `allowed_blocks` whitelist (a container, or a section). This is exactly what you want for child blocks that only make sense inside one specific parent block. `blocks/product-price.liquid` ```liquid {{ product.price | money }} {% schema %} { "name": { "en": "Price" }, "category": "content", "private": true } {% endschema %} ``` Because `product-price` is `private` **and** listed in the `details` container's `allowed_blocks` above, it: - never appears in the section-level "add block" picker, - only appears when adding into the `details` container of a `product-card`, - cannot be placed anywhere else — by construction, not by convention. `private` is the right tool for "child-only" blocks. It differs from a section's `is_creatable: false` (which means "cannot be added at all"); a private block *can* be added, but only where it is whitelisted. ## `allowed_blocks` Whitelist `allowed_blocks` is a list of block names that a **target** accepts. It can be declared in three places: ### On a layout block schema On a layout block, `allowed_blocks` whitelists which child blocks may be added into its containers. When a container also declares `allowed_blocks`, the container-level list takes precedence for that container. ### On a layout block container Restricts which blocks may be added into that container (see [Layout blocks](#layout-blocks-and-containers)). ### On a section schema Restricts which blocks may be added at the section's top level. `sections/main-product.liquid` ```liquid