wire-component-default-data
When to use
Add per-prop defaultValue to a registered Studio component so it renders visibly the moment an author drops it on the canvas, before any data binding.
Use when registering (or revisiting) a component that needs placeholder content the instant an author drags it from the palette, before any prop is bound. Also for triaging "component renders blank after drop", empty palette previews, blank array items. Phrases: "set default value", "blank on drop", "palette preview empty". Defaults are UX requirement, not polish.
Mandatory 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.
Wire Component Default Data
Context
Studio renders a component the moment it's dropped on the canvas, long before the author wires any prop to entry data. If the props schema passed to registerComponent doesn't set defaultValue on each visible prop, the canvas shows empty rectangles, missing images, and unlabeled buttons. Authors read that as "broken", not "unbound".
Reference: docs/30-look-it-up/05-reference/62-data-sources.md.
Mental model:
defaultValuelives on each prop, never on the component as a whole.- Defaults apply only when a prop is unbound and not explicitly cleared. The moment the author binds the prop to
template.*,contentstack.*, repeater context (e.g.repeater.title), or a static value, the binding wins. - If the author clears a field (empty string / null), Studio respects the explicit empty: it does not fall back to the default.
defaultValueis different fromdefaultValueHint:defaultValue: real value passed to the component until overridden.defaultValueHint: placeholder text inside the form input only, never reaches the component.
Use defaults for palette preview + pre-binding state. Use bindings for real authored content.
Task
-
Open the registration file at
registrationFileand locate theregisterComponent({ type: "<componentType>", ... })call. -
List the props that contribute visible structure: text, images, choice variants, link labels, repeated items. Behavioral props (callbacks, ids, analytics tags) generally do not need defaults.
-
Set per-prop
defaultValuematching each prop'stype. Use this template:registerComponent({type: "Hero",component: Hero,props: {headline: { type: "string", defaultValue: "Your headline here" },subtitle: { type: "string", defaultValue: "Short description of this section" },image: { type: "imageurl", defaultValue: "/placeholder-hero.png" },size: { type: "choice", options: ["small", "medium", "large"], defaultValue: ["medium"] },cta: {type: "object",properties: {label: { type: "string", defaultValue: "Get started" },href: { type: "href", defaultValue: "#" },},},features: {type: "array",items: { type: "string", defaultValue: "Feature item" },defaultValue: ["First feature", "Second feature", "Third feature"],},},});Rules by type:
choicedefaults: write an array (defaultValue: ["medium"]). It works for single- and multi-select on every SDK version. Multi-select requires it. Fromstudio-registry1.7.0, single-select also accepts the bare value ("medium") and converts it to an array. Before 1.7.0 a bare value renders with nothing selected.objectparents do not take their owndefaultValue: each child prop owns its default.arrayprops need two defaults: outerdefaultValue(initial items the canvas shows) anditems.defaultValue(each new row added later).imageurldefaults must resolve: ship the placeholder asset alongside the component bundle atplaceholderAssetPath.
-
Use placeholder phrasing, not marketing copy. Defaults ship as-is if the author forgets to bind.
- Good:
"Your headline here","Short description of this section","Feature item". - Bad:
"Buy our amazing product today!".
- Good:
-
Default
choiceprops to the safest / most common variant (size: ["medium"],tone: ["neutral"]), not the rarest. -
Decide between
defaultValueanddefaultValueHintper prop. If you want guidance text in the form input only (and a blank canvas is fine for that prop) use the hint instead:title: {type: "string",defaultValueHint: "e.g. Welcome to our site",}Reach for
defaultValuewhen the canvas must not render blank. Reach fordefaultValueHintwhen blank is fine but the form needs a nudge. -
For complex components (heroes, cards with many regions) pre-populate a coherent stub set across every visible region so the dropped component reads as a recognizable shape, not a half-rendered skeleton.
-
Ship any referenced placeholder assets. If a
defaultValuepoints at/placeholder-hero.png, add that file to the project'spublic/(or framework equivalent) and confirm it loads. A broken image is worse than no image.
Defaults vs binding: when each applies
| Situation | What renders |
|---|---|
| Prop unbound, no author input | defaultValue |
Prop bound to template.title / contentstack.* / repeater.<field> | Bound value (default ignored) |
| Author cleared the field (empty string / null) | The empty value: Studio does NOT fall back to default |
validate rejects every value | Default still renders, but a validation error shows in the form |
Inputs needed from the user
In this order. If any is missing, ask before editing code.
componentType: thetypestring used at registration.registrationFile: path to the file callingregisterComponent.placeholderAssetPath: optional, only required if the component has image props.
Acceptance
This skill succeeds only when ALL of the following are true. If any fails, surface the failure and stop.
- Every visible prop on the component has either a
defaultValueor a deliberatedefaultValueHint. -
choicedefaults are arrays (["medium"], not"medium"). - No
objectparent has its owndefaultValue. Each child prop owns its default. - Every
arrayprop has both outerdefaultValueanditems.defaultValue. - No default contains real marketing copy.
- Every
imageurldefault resolves (the placeholder file exists inpublic/). - Rebuilding the canvas app, refreshing Studio, and dragging the component onto an empty canvas renders every region with placeholder content, verified by inspecting a PNG screenshot of the canvas iframe (a11y snapshots are opaque to iframe contents).
- Binding one prop to
template.*replaces the default. Unbinding restores the default.
Common pitfalls
| Pitfall | Why it bites | Fix |
|---|---|---|
choice defaults written as strings | Multi-select, or studio-registry before 1.7.0: silently falls back to the first option or blank | Wrap in an array: ["medium"] |
defaultValue on an object parent | Has no effect. Only child props take defaults | Set defaults on each child prop |
Forgetting items.defaultValue on arrays | Initial items render. "Add item" produces a blank row | Set both outer and items.defaultValue |
Confusing defaultValue with defaultValueHint | Hints never render on the canvas: component appears blank on drop | Use defaultValue when canvas must not render blank |
| Real marketing copy as defaults | Authors leave it in place and it ships to production | Use placeholder phrasing like "Your headline here" |
| Expecting defaults to back-fill after a clear | Studio respects explicit empties | If a default is needed, don't let the author clear |
| Image defaults that 404 | Broken placeholder is worse than no image | Ship the asset alongside the bundle |
See also
docs/30-look-it-up/05-reference/62-data-sources.md: full reference.- Pair with
register-studio-componentwhen you're introducing the component for the first time. - Pair with
bind-prop-to-templateonce the component renders and the author is ready to wire real data. wire-slot-data: when the values a child needs come from the component that owns its slot, not from a static default.