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.

tsx
{
  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

TypeEditor controlProp value
stringtext field, or a select when options is setstring
longTexttextareastring
richTextformatting toolbardocument object
numbernumeric fieldnumber
booleanswitchboolean
colorcolour picker with your brand palettestring
filemedia libraryURL string
listrepeatable rows of subFieldsarray of objects
blocksa drop target for other blocksrendered children
tsx
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.

tsx
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.

tsx
<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