Skip to content

BlockDescriptor

type BlockDescriptor = {
atomic?: boolean;
continueAs?: string;
disableToolbar?: boolean;
fromMarkdown?: (ctx) =>
| BlockMarkdownParseResult
| null;
multilineText?: boolean;
name: string;
nestable?: boolean;
supportsDecoration?: boolean;
toComponent?: (payload) => unknown;
toDOM?: (payload) => HTMLElement;
toMarkdown?: (payload, ctx) => string | string[];
toolbar?: | ToolbarItem
| ToolbarItem[];
type: "standalone" | "inline";
};

Defined in: blocks.ts:73

PropertyTypeDescriptionDefined in
atomic?booleanWhether this block is “atomic” (non-text, non-nestable, treated as a single unit by the editor). Atomic blocks have no editable content and cannot be split or merged; they can only be inserted or deleted as a whole. Examples include images, dividers, embeds, etc.blocks.ts:86
continueAs?stringBlock type to use for the right-hand block when Enter splits this block. Defaults to the same type (standard paragraph-style behavior). Set to 'paragraph' for “structural” blocks (callouts, quotes, headings, etc.) that should not propagate themselves on Enter — the caret continues in a fresh paragraph instead of cloning the block. Notion uses this for headings, callouts, quotes, and dividers.blocks.ts:96
disableToolbar?booleanOpt out of (or into) the floating block-transform toolbar when this block type appears in the block-handle selection. - undefined (default): the toolbar hides automatically when the block is atomic: true (image, divider, counter, embed) — applying a “Heading 1” turn-into to an atom would destroy its attrs and replace it with an empty heading. Non-atomic blocks show the toolbar normally. - true: always hide, even for non-atomic blocks (e.g. a custom text-bearing block whose attrs would be lost on type-change). - false: always show, even for atomic blocks (rare; e.g. an atom that does want to participate in transforms). When any selected block opts out, the toolbar stays hidden in block-mode regardless of mixed selection contents. Text-selection mode is unaffected — bold/italic/etc. still apply to text inside blocks that have decoration support.blocks.ts:168
fromMarkdown?(ctx) => | BlockMarkdownParseResult | nullParse one or more lines of markdown into a block of this type. Called by parseMarkdown (in @plim/markdown) when this descriptor is registered. Receives the current line plus the surrounding cursor so multi-line shapes (fenced code, callouts spanning blocks) can peek ahead. Return null if this descriptor does not match the line — the parser will try the next descriptor and finally fall through to built-ins. Return {block, consumed} to claim ≥1 line(s); consumed is how many input lines this match ate. Rationale: this is the dual of toMarkdown. Without it, copying a callout (which serializes via toMarkdown as > [!INFO] …) and pasting it back parses as a built-in quote block — losing the callout type and any tone attrs. With fromMarkdown registered, the roundtrip is lossless even across plain markdown channels.blocks.ts:140
multilineText?booleanIf true, plain Enter inside this block inserts a literal \n into the block’s text (line break) instead of splitting into a new block, and ArrowDown / ArrowRight at the end of the last visual line / end of the block exits to the next block — creating a fresh paragraph underneath if no next block exists. Code blocks set this so users can compose multi-line code without each Enter creating a new code block, while still being able to escape downward via arrow keys (Notion’s behavior). Shift+Enter (which already inserts \n) is unaffected.blocks.ts:108
namestring-blocks.ts:74
nestable?boolean-blocks.ts:76
supportsDecoration?booleanWhether this block can be decorated with marks (default true if text-bearing)blocks.ts:81
toComponent?(payload) => unknown-blocks.ts:110
toDOM?(payload) => HTMLElement-blocks.ts:109
toMarkdown?(payload, ctx) => string | string[]Serialize this block to one or more lines of markdown. Receives the block payload (with textContent already flattened from spans) and a serializeInline(spans) helper that emits inline markdown for an arbitrary span array using the registered marks. Return either a single string (one line) or an array of strings (multiple lines for fenced/multiline content). Children are serialized separately by the walker and indented automatically; do not include child output here. If unset, the serializer falls back to textContent as a plain paragraph line — fine for most text blocks; structural blocks (image, divider, callout chrome) should set this explicitly.blocks.ts:123
toolbar?| ToolbarItem | ToolbarItem[]Items this block contributes to the floating selection toolbar — most commonly “turn into” transforms (e.g. heading levels, paragraph, quote). Each item’s visibleWhen decides whether it shows up. By default the toolbar renders block items only when the selection is non-empty; supply your own visibleWhen to override.blocks.ts:148
type"standalone" | "inline"-blocks.ts:75