Skip to Content
For DevelopersDefining components

Defining components

A component is a user-definable block type. Each key in config.components is a component name that appears in the Blocks palette and in the saved document’s type field.

import type { Config } from "@useblok/core"; const config: Config = { components: { Hero: { /* see below */ }, Features: { /* ... */ }, }, };

ComponentConfig shape

interface ComponentConfig<Props> { label?: string; // Shown in the library + inspector description?: string; // Short subtitle in the library icon?: ReactNode; // Rendered in library row + layers tree accent?: string; // Color for the icon tile (any CSS color) folder?: string; // Groups in the Blocks palette tags?: string[]; // Used by library search fields?: Fields<Props>; // Auto-form definition tabs?: TabConfig[]; // Optional grouping of fields defaultProps?: Props; // Values used when the block is inserted render: ComponentType<Props>;// Canvas renderer — required preview?: ReactNode; // Optional palette thumbnail getSummary?: (p: Props) => string; // Shown in Layers + row headings version?: number; // Current schema version (default 0) migrations?: BlockMigration[]; // See the Migrations page }

Minimal example

Hero: { label: "Hero", fields: { title: { type: "text", label: "Title", required: true }, }, defaultProps: { title: "Hello" }, render: ({ title }) => <h1>{title}</h1>, }

Richer example

Hero: { label: "Hero", description: "Big banner with headline, subtitle, and CTA.", icon: <Sparkles size={16} />, accent: "#6366f1", folder: "Marketing", tags: ["banner", "top", "landing"], tabs: [ { id: "content", label: "Content" }, { id: "style", label: "Style" }, ], fields: { title: { type: "text", label: "Title", tab: "content", required: true }, subtitle: { type: "textarea", label: "Subtitle", tab: "content", rows: 3 }, cta: { type: "link", label: "Button", tab: "content" }, align: { type: "select", label: "Alignment", tab: "style", options: [ { label: "Left", value: "left" }, { label: "Center", value: "center" }, ] }, }, defaultProps: { title: "Hello", subtitle: "", align: "center" }, render: ({ title, subtitle, cta, align }) => ( <section style={{ textAlign: align, padding: 48 }}> <h1>{title}</h1> {subtitle && <p>{subtitle}</p>} {cta?.url && <a href={cta.url}>{cta.label}</a>} </section> ), getSummary: (p) => p.title as string, }

render — the canvas component

Your render function receives the block’s props object. It’s a regular React component — render whatever you want.

render: (props) => ( <section> <h1>{props.title}</h1> {props.subtitle && <p>{props.subtitle}</p>} </section> )

The blok helper (slots)

If your block has a slot field, the render function receives an extra blok helper with a renderSlot(name) method:

Container: { fields: { children: { type: "slot" } }, render: ({ blok }) => ( <div style={{ padding: 24 }}> {blok.renderSlot("children")} </div> ), }

See the root component page for how the root’s children plugs in.

defaultProps

Used as the initial prop values when the block is inserted from the palette. A block’s id is generated automatically — don’t include it in defaultProps.

defaultProps: { title: "Hello", subtitle: "", align: "center" }

getSummary

Short label (usually the block’s main text) shown in:

  • The Layers tree
  • The Edit panel row header
  • The breadcrumb when drilling into slots
getSummary: (props) => props.title as string

Return an empty string (or omit the function) if no sensible summary exists.

version + migrations

When your props shape changes in a backwards-incompatible way (renamed field, restructured object), bump version and add a migration. See Migrations.

Type-safe components

For full prop autocomplete and type-checking in render, fields, and defaultProps, pass the props type as a generic:

type HeroProps = { title: string; subtitle: string; align: "left" | "center" }; const Hero: ComponentConfig<HeroProps> = { label: "Hero", fields: { title: { type: "text", label: "Title" }, subtitle: { type: "textarea", label: "Subtitle" }, align: { type: "select", label: "Alignment", options: [...] }, }, defaultProps: { title: "Hello", subtitle: "", align: "center" }, render: ({ title, subtitle, align }) => <section>{/* ... */}</section>, };

Categories

Organise the Blocks palette:

categories: { marketing: { title: "Marketing", description: "Hero, CTAs, grids." }, layout: { title: "Layout" }, }

Components are placed in categories by their folder field. You can also set components: ["Hero", "Features"] on a category for an explicit list.

Last updated on