Blocks
The block vocabulary of an article's body and an answer — prose blocks and typed widgets.
An article's body and a question's answer are arrays of blocks. Every block has a _type. There are two families:
- Prose blocks: headings, paragraphs, lists, quotes, images, code.
- Typed blocks: widgets with a fixed shape that your site renders with its own components.
A _type you don't know: skip it (and log it, if you like). New block types are added without a new protocol version, so a receiver must never fail on one.
Prose blocks
_type | Shape |
|---|---|
heading | { "_type": "heading", "level": 1, "text": "…" }, level 1 to 4 |
paragraph | { "_type": "paragraph", "text": "…" } or with "children": [inline nodes] |
bulletList | { "_type": "bulletList", "items": ["…", "…"] } |
numberedList | { "_type": "numberedList", "items": ["…", "…"] } |
blockquote | { "_type": "blockquote", "text": "…", "cite": "…" }, cite optional |
image | { "_type": "image", "url": "https://…", "alt": "…", "caption": "…" }, caption optional |
code | { "_type": "code", "language": "ts", "code": "…" }, language optional |
Inline nodes
A paragraph's children are inline nodes, also keyed by _type:
_type | Shape |
|---|---|
text | { "_type": "text", "text": "…" } |
link | { "_type": "link", "url": "https://…", "text": "…" } |
entityLink | A link to an entity your site defines |
sourceCitation | { "_type": "sourceCitation", "source_id": "src-1" }. Render only when the page's sources has that id; see citations. |
Internal links arrive already resolved to your page URLs; a link to a page that isn't live yet arrives as plain text.
Treat every string as text. Blocks are written by a model and an editor; render them as text, never as HTML, and only follow http(s), mailto, tel and site-relative URLs.
Typed blocks
statBar
layout is "horizontal" (default) or "vertical"; 2 to 5 stats.
checklist
faq
prosCons
howItWorks
cta
title, buttonText and buttonUrl are required.
linkGrid
columns is 2, 3 (default) or 4.
featureGrid
columns is 1, 2 (default) or 3.
featureList
Icons
icon strings name an icon from a set your site chooses (for example Lucide). Render the block without the icon when you don't know the name.
Site-specific blocks
The JSON schema also defines blocks that only some receivers render:
hubListing:{ "_type": "hubListing" }, optionally withsize("small"or"large"),m,l,dandqto freeze a search. It marks the spot where your site inserts a live listing of its own (at most one per article). If you have nothing to place there, render nothing: no heading, no empty state, no spacing.priceComparison,seasonCalendar,searchBox: used by receivers that declare them throughcomponents-condensed.
If you don't implement one of these, skip it like any unknown type. It must never show as visible output.