When to Use
The pitfall table for authoring a Section: what fails silently on the canvas, why, and the fix. Read before reporting a Section done.
Part of the Section-authoring set. Start at build-section.
Common Pitfalls
| Pitfall | Why it bites | Fix |
|---|---|---|
| Trying to link the section to a scalar field (title, description, image) | Studio’s picker doesn’t offer scalar fields: a section composes UI against a shape, not a value | Pick the parent Group / Global Field / CT / Block. Expose individual props later via Expose Section Prop |
| Linking to a multi-variant schema without dropping a Repeater | Section composes against the whole list as one shape. Renders only the first item or fails to bind | When isMultiple=y, drop a Repeater bound to the array path and place components inside it |
| Picking Modular Block instead of a specific Block type | Bindings are typed against the union of block shapes: most fields don’t resolve | If the section is for one block type, pick block and select that specific block. If the section handles many, use Repeater + Condition Block per block type |
| Skipping Connect A Schema | Section is static-only. Won’t auto-bind on templates. Authors wire every value by hand | Pick a structural schema. Only skip when you know the section is purely presentational |
| Binding a prop to a field that isn’t in the Data Picker (forcing a path, keeping a stale binding to a removed field) | The bind resolves to undefined at runtime, so the component falls back to its registration defaultValue. The canvas shows plausible-looking placeholder content, so the break is invisible until production renders empty. | Field-existence gate (Step 5d): only bind fields the picker offers. When the field is missing, fix the linked schema or the CT (migrate-ct-schema). Never force the bind. |
| A whole-array/object component prop with no multi-valued field on the CT (e.g. Article Grid bound to articles on a CT that has no articles reference) | Nothing to bind the collection to, so the component renders its default array forever (ARTICLE ONE / TWO / THREE). Looks like it “works” in Design Mode. | Collection-source gate (Step 5e): add the multi-Reference / Modular Block / multiple Group, or pin a query, or decompose to Repeater + atomic child Section (build-repeating-section). |
| Reading Design-Mode placeholder as real bound data | Design Mode renders registerComponent defaults. A broken bind and a working bind look identical there. Ship it and production is empty. | Always verify in Preview Mode (Step 5f). If Preview still shows the generic defaults, the bind didn’t resolve. Re-check field existence + source. |
| Dropping Studio default components instead of Registered Components | No brand consistency. Section ignores the project’s component library | Switch palette category to Registered Components before dragging |
| Skipping the Expose Props step on Save | Template authors get a locked section, no value overrides possible | Toggle the props that should be overridable in the Expose Props modal |
| Assuming the Section is broken because the canvas shows defaults, not CMS values | Design Mode renders registration defaults. Preview Mode renders real bindings. See use-repeater for the two-mode model. | Toggle Preview Mode in Properties, then Configuration. |
| Binding inside a Repeater without a Condition Block on references / modular blocks | Iteration items are polymorphic. Bindings silently fail | Wrap with Condition Block (single-CT references included) |
| Picking from the Section’s linked-schema root for a prop that sits inside a Repeater | Wrong scope: every iteration shows the same value (the parent’s field), not the per-item value | Inside a Repeater, the Data Picker switches to the iteration item’s fields automatically. Bind from that root |
| Naming the section “Section 1” / “New Section” | Authors cannot tell sections apart in the palette | Use an intent-revealing name like Hero Strip, Card Grid, Testimonial Card |
| Dropping a Rows / Box wrapper before the first real component | Leaves a visible “Drop Here” placeholder zone in the canvas (and in every screenshot) that authors must clean up later. Rows is an e2e-test scaffolding habit, NOT a Studio authoring pattern. | Drop the first component directly onto the canvas root slot. Wrap in a container ONLY when you need explicit layout (e.g. an hstack to put two cards side-by-side). |
| Adding a Repeater for a single, non-list use case | Repeater iterates a multi-valued field. A static page with one Hero + one Product Card needs zero iteration. Adding one introduces a phantom iteration scope and shifts the Data Picker so the parent Section’s fields aren’t reachable from inside. | Use Repeater ONLY when the linked field is genuinely a list (Modular Block list, multi-Group, multi-Reference, multi-entry pinned query). For a single hero or single card: drop the component directly. |
| Path A when the card visual may be reused elsewhere | Locks the card into one parent. Reuse contexts drift out of sync | Default to Path B (see § Path A vs Path B). |
| Slot inside Repeater without a sized layout container | Child stretches full canvas width | Wrap in grid/flex/max-width Box. See use-section-slot § Layout container. |
| Leaving empty “Drop Here” zones at the bottom of the canvas | Saved compositions render those zones as visible placeholders in screenshots and to authors browsing the section gallery. | Before Save, switch to Layers and delete any orphan empty Box / Slot rows. Acceptance: the Layers tree contains ONLY the components you intended. No orphan structural wrappers remain. |
| Typing a Tailwind (or any scanned-utility) class into the Design panel and seeing no effect: the class is on the element in DevTools with no rule behind it | Tailwind emits CSS only for classes it finds while scanning source files. A composition is JSON in Contentstack, not a file in the repo, so a class that exists only in the Design panel is never generated. Identical symptom to a typo’d class name. | Keep load-bearing utilities in source: put the layout on a registered component, or list the class in Tailwind’s safelist so it is always emitted. Reach for the Design panel for values the design system already ships. |
| Assigning a CSS class to a Basic box and expecting display: flex/grid to apply: the box renders but the children stack vertically (no flex) or single-column (no grid). | The Basic Box component is just <div {...rest} {...studioAttributes}>. Studio renders box layout from the node’s styles.default.responsiveStyles.default (set via the Design panel on the node) and surfaces it through the renderer’s style pipeline. An external CSS class on the app side has no node-level styles to attach to and only applies whatever rules its stylesheet defines. It does NOT make Studio’s renderer emit display: flex. | Author Basic-box layout via node responsiveStyles in the Design panel: select the Box, open the Design tab, then set display, gap, alignItems, flexDirection, etc. The renderer writes these into the DOM. Reach for a CSS class only for tokens/colors/typography already wired through your design system, never for the load-bearing layout shape. (Custom registered components are different: they can apply layout via their own React/CSS.) |