use-condition-block
When to use
Wrap component bindings inside a Repeater with sibling Condition Blocks (one per block / content type) so each iteration item resolves to a specific schema before fields bind. Use Studio UI, driven through Playwright per drive-studio-canvas-ui. Don't hand the clicks to the user or switch to the API unless they ask; that's author-composition-via-api.
Use whenever a Repeater iterates a Modular Block list or a Reference field. Without sibling Condition Blocks the iteration items have no resolved schema and every binding shows empty. Phrases: "modular block repeater", "reference repeater", "blocks render empty". Do NOT use for plain multi-valued fields (text/number arrays don't need schema disambiguation): skip Condition Block entirely.
Auth preflight: settle the credential before the first API call. Resolve it OAuth-first per
authenticate-cma:CS_OAUTH_ACCESS_TOKEN, else the Contentstack MCP's stored session: Read that skill for where it is, even with no MCP connected. Never ask the user for a sessionauthtoken. If nothing resolves, or a refresh fails with400 invalid_refresh_token, hand them! CONTENTSTACK_REGION=<code> npx @contentstack/mcp --auth(it needs a TTY and a browser, so it cannot be run for them) and wait.403 error_code 316is a valid credential aimed at another org: fix the org or theapi_key, do not re-authenticate.
Use a Condition Block
Context
A Condition Block narrows the iteration item inside a Repeater to a specific schema (a Modular Block type, or a referenced content type) so that field bindings underneath it resolve. Without it, Studio cannot know which schema a given iteration item has, so the Data Picker cannot offer typed fields and the canvas surfaces the hint Add a condition for <ct> schema, then bind the component within it to the hover fields. Accepting that hint auto-wraps the binding in a Condition Block: this skill is the manual, deliberate equivalent.
Model: one Condition Block per type, as sibling children of the Repeater. Studio's Add Condition modal lets you tick multiple block types or content types in one go. It inserts one Condition Block per selected UID, all as siblings under the Repeater. There is no "multi-branch" mode where one Condition Block routes between several types: each CB narrows to exactly one type via its condition.type metadata (modular_block matched to a block UID, or reference matched to a content-type UID).
Condition Blocks are required inside a Repeater for:
- Modular Block lists with two or more block types (the iteration item could be any one of them).
- Reference fields with multiple content types (the related entry could be any one of the allowed CTs).
- Reference fields with a single content type: still required, because Contentstack composition schema narrows iteration item type via the Condition Block before
repeater.<field>paths resolve. One Condition Block matching the single CT is enough.
Condition Blocks live in the palette under Smart Containers. Reference: docs/15-build/15-data/22-show-or-hide-content-with-a-condition.md.
Task
-
Confirm a Repeater exists bound to the Modular Block or Reference field named in
repeaterSource. If not, stop and runuse-repeaterfirst: a Condition Block has nothing to discriminate without a parent Repeater iteration scope. -
Open the Add Condition modal. It opens when you bind the Repeater's
itemsto the field: never click Skip. Re-binditemsto reopen it (it lists only types without a Condition Block yet), or accept the data picker's Add Condition prompt on a child of the Repeater. No Repeater action opens it. The modal lists every block type (Modular Block source) or content type (Reference source) the Repeater's binding allows. -
Tick every UID in
branches(in any order: Studio inserts them as siblings under the Repeater. Their order doesn't change the output: each item renders through the one branch that matches it, and items appear in the data's order). Confirm. Studio creates one Condition Block per selected UID, each with its discriminator (modular_blockblock UID, orreferencecontent-type UID) recorded ascondition.typemetadata on the Condition Block node, not as a path expression the user writes. -
For each newly-created Condition Block, drop a component into the Box Studio placed inside it (a Condition Block takes one child) and bind the component's props via the Data Picker. The Data Picker surfaces the Repeater Data root inside a Condition Block, narrowed to the fields of the type that Condition Block matches: pick from there. Use Component Default Data only for runtime values not tied to the iteration item.
-
Save the composition and verify in Preview Mode. Select the parent Repeater in Layers and toggle Preview Mode in Properties, then Configuration. Conditions apply their real type checks only in Preview Mode. In Design Mode (the default) you see the un-evaluated branch with placeholder data. Step through iterations and confirm each item routes through its matching Condition Block. Items whose UID matches none of the inserted Condition Blocks render nothing: there is no built-in default fallback.
Inputs needed from the user
In this order. Stop and ask if any is missing: DO NOT guess branches.
compositionName: Section or template canvas in scoperepeaterSource: parent Repeater binding (e.g.blog_post.body_blocks)branches: comma-separated block-type or content-type UIDs
If repeaterSource is a Reference and the user gives only one UID, still create a single-CB setup: single-CT references are NOT exempt from the Condition Block requirement.
Acceptance
This skill succeeds only when ALL of the following are true. If any fails, do not claim success: surface the failure and stop.
- In Layers the tree reads
Repeater > [Condition Block × N]: each Condition Block is a direct child of the Repeater, or of the one Box that is the Repeater's only child (for Visual Editor's item tags:make-visual-editor-editable§ 2), never wrapping it. - There is exactly one Condition Block per UID in
branches. UIDs not inbranchesdo not have a Condition Block. - Each Condition Block's
condition.typemetadata is set tomodular_block(Modular Block source) orreference(Reference source), matched to a specific block / content-type UID, never to a shared field name liketitle. - Inside each Condition Block, the type-specific component's props are bound via
repeater.<field>paths. The Data Picker shows the typed fields of that Condition Block's schema, not a generic union. - With Preview Mode toggled on the parent Repeater, each iteration item visibly renders through its matching Condition Block. No item shows the "Add a condition for
schema" hint. - The user is informed that items whose type matches none of the inserted Condition Blocks render nothing (no built-in fallback). If that is unwanted, the user must add additional Condition Blocks for those types.
Common pitfalls
| Pitfall | Why it breaks | Fix |
|---|---|---|
| Trying to add multiple "branches" to a single Condition Block | Each Condition Block narrows to exactly one type. There is no multi-branch model | Insert sibling Condition Blocks (one per type) under the Repeater |
| Condition Block wraps the Repeater | Discriminates the parent scope, not the iteration item. repeater.<field> still cannot resolve | Drop Condition Block INSIDE the Repeater as a direct child sibling |
Trying to write a path expression for the discriminator (e.g. block.type === "hero") | Studio stores the discriminator as condition.type metadata on the node, not as a user-written path expression | Pick the block / content-type UID in the Add Condition modal. Studio handles the discriminator under the hood |
| Skipping Condition Block for single-CT Reference | Picker shows generic union, repeater.<field> paths fail to resolve | Add one Condition Block matching that single CT |
| Binding fields directly under Repeater on a Reference / mixed Modular Block | Canvas shows Add a condition for <ct> schema hint. Bindings stay broken | Accept the hint OR add Condition Blocks via the modal per this skill |
| Expecting an unmatched-fallback Condition Block | No such affordance in Studio: items with unmatched types render nothing | If you need a fallback, add a Condition Block for every type you expect. Revisit if new types are added later |
| Forgetting Preview Mode when verifying | Repeater renders only one iteration by default. You cannot see whether each Condition Block routes correctly | Select Repeater in Layers, toggle Preview Mode in Properties |
See also
docs/15-build/15-data/22-show-or-hide-content-with-a-condition.md: referencedocs/15-build/15-data/20-render-a-list.md: parent containerdocs/25-learn-by-example/05-guides/30-seasonal-landing-page-walkthrough.md: Modular Block recipe in action