Anatomy of a block
Every block has four parts:
A block is defined once with
defineBlock, registered once with registerBlock, and instantiated many times through createBlockInstance.
A simple block
A button with one prop — a text label. The renderer creates a real DOM element and useseffect() to keep it in sync with block.props.
as const satisfies JSONSchema plus FromSchema<typeof schema> keeps the schema and the renderer’s prop types in sync — change the schema, the TS types update.
A more advanced block
A card block with multiple typed props, nested slots, and a preset shown in the Editor’s picker.- Typed props.
variant,size, andshowThumbnailare fully typed inside the renderer. - Slots. A slot can be a single block, an array of blocks, or a plain string.
createBlockInstancebuilds a nested block by name and merges overrides into its defaultinitialValue. - Presets. Each preset provides a complete
statesnapshot (props + slot contents) — a named starting point for a block instance.
Block groups
Every block declares agroup that identifies its origin:
All three groups are first-class — there’s no behavioural difference between them.
Registering blocks
registerBlock adds the definition to the registry so it can be instantiated by name. Call it once at the top of the package entry file: