Skip to main content

Component schema: props, types and defaults

Look up what you can declare in a component's props when you register it: the fields every prop takes, the prop types, each type's options, how defaults work and which props can control design. For the registration call itself, see Register a component.

The example on this page is a team blog. Its Blog post content type is blog_post, and the entry AI 101 lives at /blog/ai-101. BlogHero, in src/components/BlogHero.tsx, has the props title, summary and image. AuthorCard is the blog's compound, with the props name, photo and link. This page keeps it because its three props show three prop types. The Author card section itself is built in Studio from smaller pieces. See From a design to components.

Schema shape​

props maps each prop name to its declaration. The name is the prop your component receives.

props: {
title: { type: "string", displayName: "Title", placeholder: "Your post title" },
summary: { type: "string", displayName: "Summary", control: "large" },
image: "imageurl",
}

image: "imageurl" is the short form. It works for a type that needs no options: string, number, boolean, datestring, href, imageurl, array, object and slot. A short array takes items of any type, and a short object has no properties. choice, plaintext, json_rte and any need the full form.

Every prop takes these fields.

FieldRequiredWhat it does
typeYesOne of the prop types.
displayNameNoThe label in the Settings tab.
defaultValueNoThe value a newly dropped component starts with. See Default values.
helpTextNoText behind a help icon next to the field in the Settings tab.
designNotrue makes the prop control a CSS property. See Props that control design.

Studio ignores any other field, so default: in place of defaultValue: does nothing.

To make a bound value editable in Visual Editor, your component also reads a $ prop for each bound prop. That's in Make bound values editable in Visual Editor.

The prop types​

TypeYour component receivesControl in the Settings tabCan be bound to
stringA stringA text box. control can make it larger or a Markdown editor.Text fields. Number and boolean fields pass too.
plaintextA stringA text box, like stringSingle-line and multi-line text, number and boolean fields only. Not rich text, Markdown or multiple fields.
numberA numberA number box, or a sliderNumber fields
booleantrue or falseA toggleBoolean fields
choiceOne string, or a list of strings with multiSelect: trueRadio buttons, or a dropdown. With multiSelect: true, checkboxes.Text fields
hrefA stringA URL box that shows URL is invalid on a bad value. It's not a link picker.Text fields
imageurlA stringChoose a file, Upload a file and Enter URLText fields, such as a file field's url
datestringA stringA date picker, or a date and time pickerDate fields
arrayA listAn editable listMultiple-value fields, such as modular blocks. A query result gives its entries.
objectAn objectA nested formGroup and JSON fields
slotRendered React contentA drop zone on the canvasNothing. Authors drop components into it.
json_rteThe JSON RTE document, plus a jsonConfig propA JSON editorJSON RTE fields
anyAny valueA text box, or a JSON editor for a JSON RTE valueAnything

There's no separate multi-choice type. It's choice with multiSelect: true.

For any, an object with a single key is unwrapped to its value, and that repeats down the tree. Use any only for plain values, and pick object or array for structured ones.

To render a json_rte value, see Render rich text and embedded entries.

Slot props​

A slot prop gives your component a drop zone. Authors drop components into it on the canvas, and your component receives what they dropped, already rendered. BlogHero is the compound the blog keeps on purpose, for its one fixed hero treatment. To give BlogHero a drop zone under the summary, for a share button, declare a slot and render it where the drop zone goes.

props: {
actions: { type: "slot", displayName: "Actions", helpText: "Drop a button here" },
}
<p>{summary}</p>
<div>{actions}</div>

For a slot, helpText is the drop zone's tooltip. A slot can't be bound, and it has no $ prop. To pass data into what's dropped in a slot, see StudioComposition and Slot props.

Give slot data a schema with dataFrom​

Data your component passes through <Slot data> reaches Studio as plain JSON. So a Repeater in the slot bound to component_props.<key> has no content type schema, and its conditions can't use Content Type or Block Name. Add dataFrom to the slot to map that key to the prop whose bound data it passes on.

props: {
posts: { type: "array", displayName: "Posts" },
postSlot: { type: "slot", displayName: "Post slot", dataFrom: { items: "posts" } },
}
<Slot data={{ items: posts }}>{postSlot}</Slot>

Studio then reads the schema for component_props.items from whatever posts is bound to. Declare a key only when its value holds the prop's entries unchanged, or sliced, filtered or sorted. dataFrom changes only the schema Studio uses. It doesn't change the data your component renders.

If an entry names a prop that isn't registered, or names another slot, registration still succeeds. The console warns [studio] Ignoring `dataFrom` entry "<key>": ... and the SDK drops that entry.

Type-specific options​

TypeOptionValuesWhat it does
stringcontrol"default", "large", "markdown"A text box, a larger text box, or a Markdown editor. The default is "default".
stringplaceholderA stringFaded text on the canvas while the prop has no value and no default. It shows only in the editor.
plaintextcontrol"default", "large"A text box, or a larger text box
plaintextplaceholderA stringPlaceholder text inside the empty text box
numbercontrol"default", "slider"A number box, or a slider
numbermin, max, stepNumbersThe range and step
choiceoptionsA list of strings, or of { value, label }What the author picks from. Values are strings.
choicemultiSelecttrue, falsetrue lets the author pick more than one. The default is false.
choicecontrol"radio", "dropdown"Radio buttons, or a dropdown. The default is "radio".
hrefplaceholderA stringPlaceholder text inside the empty URL box
datestringcontrol"date", "datetime"A date, or a date and time. The default is "date".
arrayitemsA prop declarationThe type of each item, such as { type: "string" }. Required in the full form.
objectpropertiesA props mapThe fields inside the object. Required in the full form.

Default values​

Put a default on each prop with defaultValue.

WhenWhat happens
An author drops the componentStudio copies each prop's defaultValue into the template as that prop's value. It's saved with the template and shows on your live site.
You change a defaultValue in code laterComponents already placed keep the value they were dropped with. Only new drops get the new default.
A prop has no valueThe component gets the defaultValue. With none, a string with a placeholder shows the placeholder in the editor. Otherwise it gets the type's empty value, such as an empty string.
A bound field has no valueThe component gets the same fallback. A bound field that holds an empty string or null passes that through instead.
The prop controls designThe defaultValue becomes the value at the default breakpoint.

Write choice defaults like this.

ChoicedefaultValue
Single-selectOne value, such as "left", or a list with one value, such as ["left"]
Multi-selectA list, such as ["left", "center"]

For an array, the defaultValue is the starting list, and each item an author adds in the Settings tab starts with items.defaultValue.

Because defaults ship to your live site, pick ones that show the component clearly when it's dropped and still read as placeholder copy, such as "Your post title" rather than a real headline.

Props that control design​

A design prop lets an author set one CSS property on your component, per breakpoint, from the Settings tab. Mark it with design: true. For what authors do with it, see Make your components styleable.

props: {
textAlign: {
type: "choice",
design: true,
displayName: "Alignment",
options: [
{ label: "Left", value: "left" },
{ label: "Center", value: "center" },
],
defaultValue: "left",
},
}
<h1 className={textAlign}>{title}</h1>
RuleDetail
Only two types qualifychoice, with each option's value a CSS value, and string
The prop name is the CSS propertyIn camelCase, such as textAlign, paddingInline or maxWidth
Some names are reserveddefault, className, children, style, key, ref, and the name of any style group on the component
Your component gets a class nameIt receives a generated class under the prop name, never the raw value, and has to put that class on an element
The control sits with the other propsIt shows in the Settings tab, not the Design tab

When a design prop breaks a rule, Studio doesn't throw. It drops design: true and logs a warning in the browser console, and the prop becomes an ordinary prop.

[studio] Ignoring `design: true` on prop "text-align" of component "blog-hero": "text-align" is not a camelCase CSS property.

The warning ends with one of these reasons.

ReasonWhat's wrong
type "number" is not supported (allowed: choice, string).The prop isn't a choice or string.
"style" is a reserved key.The prop name is reserved.
"title" collides with a registered style group.A style group on the component has the same name.
"text-align" is not a camelCase CSS property.The name isn't a CSS property in camelCase.

A name that has the right shape but that the browser doesn't know stays a design prop, with this warning.

[studio] Design prop "textAling" of component "blog-hero" does not match a known CSS property in this browser — its values will emit a no-op declaration.

A complete worked example​

BlogHero and AuthorCard, declared in one call. AuthorCard binds to the author_card global field through the text fields inside it. Bind name to name, photo to photo.url, and link to link.href.

import { registerComponents } from "@contentstack/studio-react";
import { BlogHero } from "../components/BlogHero";
import { AuthorCard } from "../components/AuthorCard";

registerComponents([
{
type: "blog-hero",
component: BlogHero,
displayName: "Blog Hero",
sections: "Blog · Components",
wrap: false,
props: {
title: {
type: "string",
displayName: "Title",
placeholder: "Your post title",
helpText: "Bind this to the post's title field.",
},
summary: {
type: "string",
displayName: "Summary",
control: "large",
defaultValue: "A one-line summary of the post.",
},
image: { type: "imageurl", displayName: "Image" },
textAlign: {
type: "choice",
design: true,
displayName: "Alignment",
options: [
{ label: "Left", value: "left" },
{ label: "Center", value: "center" },
],
defaultValue: "left",
},
},
},
{
type: "AuthorCard",
component: AuthorCard,
displayName: "Author Card",
sections: "Blog · Components",
wrap: false,
props: {
photo: { type: "imageurl", displayName: "Photo" },
name: {
type: "string",
displayName: "Name",
placeholder: "Author name",
helpText: "Used as the photo's alt text.",
},
},
},
]);

Bind an imageurl prop to the file's url​

An imageurl prop's value is a string, so type it string in your component. A file field holds an object, so bind the prop to the file's url inside it. The Data Picker offers only text fields for an imageurl prop. Inside a Repeater, any field can be bound. Bound to the file itself, the component gets its fallback value with no message. The fallback is the static value, then the defaultValue, then "".

If it doesn't work​

Data Mismatch Found under a prop​

The Settings tab shows Data Mismatch Found under a bound prop, and its help tooltip reads:

Expected prop type string but received object in the component registry. Remove the binding and bind with correct data.

The bound field's value doesn't match the prop's type. Bind a field of the right kind, or change the type. The message goes away once the value matches.

On your live site, the same problem logs a warning in the browser console:

Data binding type mismatch in component "blog-hero": Expected prop "title" to be string but received object. Path: ...

Your component shows "This content may not display correctly"​

The component shows this text where the content should be:

This content may not display correctly in this view. Please contact your development team to update the component so it can support this type of content.

A string prop is bound to a group, a reference or a list. Bind a text field inside it, or change the prop's type to object or array.

No properties available for the selected component​

The Settings tab shows No properties available for the selected component. The registration has no props. Add them.

A prop has no control in the Settings tab​

The type isn't one of the prop types, such as a misspelt "text". The prop can only be bound, and the browser console shows:

[NodePropInput] No renderer for prop type "text" (propKey="title"). Registered types: ... Falling back to bind-only mode.

Change it to a real type, such as "string". TypeScript also flags an unknown type when you build.

A design prop acts like an ordinary prop​

The console shows [studio] Ignoring design: true on prop, then the prop and the reason. Fix what the reason names. See Props that control design.

A new default doesn't show on components already placed​

Studio copies defaults into the template when a component is dropped. Components placed before your change keep their old value. Change the value on each one in the Settings tab, or drop the component again.

Report a problem with this page