Make a component data-aware
How to opt your component into content-list binding so marketers can wire its props to records.
1. Update schema.json
Add supportsBinding: true to any prop you want marketers to bind. Optionally restrict the compatible field types with compatibleBindingTypes:
{
"type": "blog-post-hero",
"displayName": "Blog Post Hero",
"props": {
"title": {
"type": "string",
"supportsBinding": true,
"compatibleBindingTypes": ["text"]
},
"coverImage": {
"type": "image",
"supportsBinding": true,
"compatibleBindingTypes": ["image"]
}
}
}2. Build and sync
Use the Mirin desktop app to build, preview, sync, and publish your local theme changes. The schema validator catches common mistakes before components reach marketers, such as compatibleBindingTypes set without supportsBinding, or an unknown prop type.
3. The marketer-facing experience
Each bound prop shows a chain-link icon in the property panel. Marketers click it, pick a list, pick a record, then pick a field. The renderer resolves the binding at SSR time and your component receives the literal value.
Rendering a list with content_list
For repeater-style components (a blog index, team grid, testimonials carousel) declare a content_list prop:
{
"props": {
"source": {
"type": "content_list",
"settings": {
"collectionSlug": "blog-posts",
"limit": 12,
"sort": "published_at:desc"
}
}
}
}Your component’s render signature gains a second items argument:
export function BlogPostGrid(props, items) {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.data.title}</li>
))}
</ul>
);
}Items are sanitised and coerced before your component sees them. Do not do your own escaping. The renderer pipeline already handles it.
Allowed sort keys: created_at:desc/asc, updated_at:desc/asc, published_at:desc/asc. Snake_case only. CamelCase keys like publishedAt:desc are rejected by the API.
Field type reference
| Field type | Value shape |
|---|---|
| text / richtext | string |
| number | number |
| boolean | boolean |
| date | ISO 8601 string |
| image | { url, alt } after coercion |
| url / email | string (validated scheme for url) |
| color | lowercase hex only: #rrggbb or #rrggbbaa |
| select | string from the configured enum |
| reference | record id string; resolve via internal /resolve |
| slug | URL-safe string (can be computed from another field) |
Troubleshooting
Binding shows the prop default instead of the record value.
Check the dashboard’s Health view. The binding is probably broken (record deleted, field removed, or cross-tenant).
“Reads from” chip is empty.
Your content_list is missing settings.collectionSlug. The desktop app catches this before the theme is synced.
Marketer cannot bind a number to a URL prop.
Working as designed. Set compatibleBindingTypes: ["url"] if the prop should accept URL fields.