Skip to content
BetaDocs

Create your own block type

Use a custom block type when a design recurs and editors should fill in fields instead of arranging its pieces. Each placed block keeps its own content; the type owns the shared structure and styling. This is a built-in CMS feature in Cloud and self-hosting, not a Typeroll App or Extension.

From Core 0.2.78, write/editor permission can create or change a type. Editors can also place available types and edit their values. No local development environment is required.

  • For a one-off layout, combine built-in blocks.
  • For the same content everywhere, use a global block.
  • For a section copied and edited independently, use a block template.
  • For a reusable design with editable fields, create a block type.

Prefer a composed type, built from existing blocks. It keeps their image, link, named-style and responsive behavior. Use a template type with your own HTML when built-in pieces cannot express the markup you need. A template block type is unrelated to a full Page template.

Creating custom block types is a good task to delegate to an AI agent connected to Typeroll through MCP. Describe the design, which fields people should edit and how it should behave on mobile. The agent can inspect existing blocks and starters, define the fields, build the composition or markup, and validate and preview it with Typeroll’s tools. You do not need to write the JSON, HTML or CSS yourself.

For example:

Create a reusable advice callout for this Site and Version. Give editors a
heading and advice text to fill in. Use our existing colors and spacing,
and compose it from built-in blocks if possible. Check whether a suitable type
already exists before creating one. Validate the definition, preview it with
short and long text, and place an example on a draft Page for me to review.
Do not deploy the site.

The agent uses your current Site permissions. From Core 0.2.78, write/editor access is enough to create or change a block type; administrator access is not required. Read-only access cannot save changes. The optional tr-custom-blocks recipe guides this workflow. With compact MCP discovery, ask the agent to discover the relevant tools as needed. A local repository or development server is not required.

Review the result in the editor, test its fields and inspect narrow and wide previews. Once the type is available, editors can add instances and change their content without asking an agent or editing code. Have an administrator review any custom script and test interactions before publication.

The definition and tool sequence below are references for your agent or for manual API work; you do not need to enter them by hand.

  1. Select the Site and open Blocks. Create a block type and choose a starter such as an icon list, feature cards or numbered steps.
  2. Give it a machine name and a clear label. Define the fields editors should change, rather than exposing the entire layout as HTML.
  3. Adapt its composition, or use Turn into block type… on an existing section in the page editor and select which values become fields.
  4. Use Preview with realistic text, empty optional fields and long values. Check the available narrow and wide preview sizes. Resolve validation errors.
  5. Save the type, return to a Page and add it from the block library. Edit its fields, save the Page and preview it in context before publishing.

This definition exposes a heading and a paragraph. The heading remains an H2; editors do not need to rebuild the design. It can be passed directly to create_block_type, or to POST /api/v1/sites/{siteId}/block-types.

{
"name": "advice_callout",
"label": "Advice callout",
"category": "content",
"schema": [
{ "name": "heading", "type": "text", "label": "Heading", "required": true },
{ "name": "message", "type": "text", "label": "Advice", "required": true }
],
"composition": [
{
"id": "callout",
"type": "core/container",
"data": {
"direction": "column",
"gap": "sm",
"css_class": "advice-callout"
},
"children": [
{
"id": "heading",
"type": "core/heading",
"data": { "text": "{{props.heading}}", "level": "h2" }
},
{
"id": "message",
"type": "core/text",
"data": { "text": "{{props.message}}" }
}
]
}
],
"styles": ".advice-callout { border-inline-start: 4px solid var(--color-primary); padding: 1.25rem; }"
}

A binding such as {{props.heading}} connects an editor field to an inner block. Whole-value bindings preserve types: arrays remain arrays and booleans remain booleans. Use core/text for plain field values and core/prose for rich text.

  1. Call list_block_types and read_block_type for the blocks you will use. list_block_type_starters returns complete definitions you can adapt.
  2. Call validate_block_type with the definition under definition. Errors include paths such as /schema/0/name; fix them before continuing.
  3. Call preview_block_type with the same definition and sample data: { "heading": "Before you begin", "message": "Measure the doorway." }. Inspect the returned document visually. Try long and missing values too.
  4. Call create_block_type with the definition’s top-level properties. Use the returned block_type.id when placing an instance.
  5. Call add_block for the intended Page, using:
{
"page_id": "YOUR_PAGE_ID",
"block": {
"type": "advice_callout",
"data": { "heading": "Before you begin", "message": "Measure the doorway." }
}
}

Read the Page again, save its working copy and preview before deployment. For a site version, pass the same version to all supported tools.

Use the same fields, but replace composition with template:

<aside class="advice-callout">
{{#heading}}
<h2>{{heading}}</h2>
{{/heading}} {{#message}}
<p>{{message}}</p>
{{/message}}
</aside>

{{heading}} is escaped text; the surrounding section omits its markup when empty. Rich-text fields can use triple braces. Repeating groups use {{#each items}}; link fields support a helper that avoids empty links. See the full field and template syntax.

CSS is scoped to the block. Prefer the site’s variables and named styles so the component follows the site’s design. Custom markup is sanitized; putting a script tag in it does not enable JavaScript. A separate script property is executable code and needs deliberate code review. The unsaved block preview does not execute scripts, so verify interactions in an appropriate test deployment as well. See the script permission rules.

Changing the definition affects every instance at the next deployment. Before an update, inspect Usage or call find_pages_using_block_type. Rename fields with the supported renames mapping so stored values follow the change; do not silently remove and recreate fields. Removing populated fields or changing their type can require explicit data-loss confirmation.

Export and import .tcblocks packages to reuse a type on another Site. Review imported HTML, CSS and scripts before accepting them. Deleting a type in use is blocked; replace its instances first.

For a new type, an AI agent can propose its schema, composition and responsive behavior from your brief, then validate it and show a preview. Inspect existing uses before changing a shared definition. See Personal AI connections.

validate_block_type reports no errors for the definition, and preview_block_type renders it with sample data at the widths you support. Before changing a type that is already in use, find_pages_using_block_type lists the Pages to review.