Custom components
Registering your own components and declaring their inputs.
Registration
A registration is your component plus a description of what an author may change about it.
{
component: Hero,
name: 'Hero', // stable id, stored in content
friendlyName: 'Hero', // shown in the palette
category: 'Marketing', // groups it in the palette
icon: 'megaphone',
inputs: [ /* ... */ ],
}name is stored in every block that uses the component, so renaming it orphans existing content. friendlyName is free to change.
Input types
| Type | Editor control | Prop value |
|---|---|---|
string | text field, or a select when options is set | string |
longText | textarea | string |
richText | formatting toolbar | document object |
number | numeric field | number |
boolean | switch | boolean |
color | colour picker with your brand palette | string |
file | media library | URL string |
list | repeatable rows of subFields | array of objects |
blocks | a drop target for other blocks | rendered children |
inputs: [
{ name: 'heading', type: 'string', required: true, defaultValue: 'Ship faster' },
{ name: 'body', type: 'richText' },
{ name: 'image', type: 'file', allowedFileTypes: ['png', 'jpg', 'webp'] },
{ name: 'features', type: 'list', subFields: [
{ name: 'title', type: 'string' },
{ name: 'detail', type: 'longText' },
] },
{ name: 'children', type: 'blocks' },
]Slots
An input of type blocks becomes a slot: authors drop other components inside yours. Your component receives it as a prop holding rendered children.
function Split({ heading, left, right }: {
heading: string
left: ReactNode
right: ReactNode
}) {
return (
<section>
<h2>{heading}</h2>
<div className="grid">{left}{right}</div>
</section>
)
}An empty slot renders a placeholder in the editor and nothing at all for visitors, so a container is visible and droppable before it holds anything.
Brand colours
Hand the SDK your palette and it appears first in every colour picker, so authors pick from the brand instead of typing a hex from memory.
<Content
model="page"
content={entry}
publicKey={KEY}
brandColors={[
{ name: 'Ink', value: '#16181c' },
{ name: 'Paper', value: '#fbf8f4' },
{ name: 'Signal', value: '#2f6df0' },
]}
/>Inline editing
Double-clicking text on the canvas edits it in place. This works with no integration at all: the clicked element's text is matched back against the block's own input values, including values inside list inputs. When the match is ambiguous, because two inputs hold the same string or the element holds a concatenation, editing is declined rather than guessed at, and the author uses the inspector.
All documentation · llms.txt · llms-full.txt · contentbind.com