?format=blocks serves the article body as a flat, ordered array of top-level
blocks instead of one HTML string. Everything you need to render it is on this
page.
When to choose blocks over HTML
Choose blocks when you want to render your own components for images and video. With?format=html an image is our <img> (inside a <figure> when
the author captioned it) and a video is a <div> carrying the address, not a
player; with blocks you get the image’s src, alt, caption and decorative
and the video’s src and provider as plain fields, and can pass them to your
site’s responsive image component, your CDN transform, or your own video player.
If your articles carry video, you need blocks, or you need to handle that
<div> yourself. We do not put a third-party <iframe> in the HTML we serve
you, so a video embed renders as nothing on the page until your site turns the
element into a player. Articles describes the element and
what is on it.
Choose HTML for everything else. Blocks are not a richer text model and give
you nothing extra for paragraphs and headings.
You do not have to choose per site. The two formats are two views of the same
stored render, so you can switch by changing one query parameter, and an
article requested in both formats describes the same content: same text, same
image addresses and captions, same video addresses. What differs is what a
browser does with it, which is the video point above.
The envelope
blocks is flat and in document order. Blocks never nest: there is no block
that contains other blocks, so rendering is one pass over the array.
contract_version is the version of the block shape this article was rendered
against. It is what a future change to the block shape would key off. Today it
is 1. Read it if you want to be defensive; you do not need to branch on it.
The block types
type is one of exactly these eight names. They are ours, and they are the
whole set.
Text-bearing blocks
paragraph, heading, blockquote, bullet_list and ordered_list each
carry a single field:
The fragment is a complete element, tag included: a
paragraph is
"<p>…</p>", not the text inside one. Inline formatting (bold, italic, links)
is already in the fragment, and so is the heading’s level, so a heading block
tells you whether it is an <h2> or an <h3> by what it contains.
These fragments are the same bytes ?format=html is joined from, in the same
order. That is why the two formats cannot describe different content: the text
is literally the same HTML, cut at the top-level boundaries.
The fragments are sanitised when the article is published, which is what makes
them safe to inject as HTML. There is no inline-level structure to walk: if you
need one, the html string is what you have.
html is the only pre-sanitised field on this surface. Every other field, the
media blocks’ src, alt and caption and the article’s own title,
excerpt and feature_image_url, is plain text an author typed and is not
escaped for you. Set those through the DOM (textContent, img.alt = …)
instead of building markup out of them: an author writing Kane's "winner" in
an alt box breaks a quoted attribute with no malice at all.
image
A decorative image is one the author declared purely visual: a divider, a
flourish, a repeat of the caption.
alt is an empty string on one, which is
what tells a screen reader to skip it, so binding alt straight onto your
<img> already does the right thing and you can ignore the flag. Read it if you
do something else with the field, like falling back to the caption when alt is
blank: that fallback is wrong on a decorative image.
Handle src: null by rendering nothing for that block. It means the address
did not pass our URL rules and was blanked at publish, so there is no image to
fetch.
video_embed
src is stored exactly as the author pasted it and is not normalised, so it can
be any address the editor accepted for that provider: a watch page, a share
link, a /shorts/ or /live/ page, a player or embed URL. The block carries no
video id, so if you want to build your own player you have to read the id out of
src. These are the shapes the editor accepts, and the whole set of them:
A YouTube id is eleven characters of
A-Z a-z 0-9 _ -; a Vimeo id is digits.
Reading it back out covers every row above:
provider as an open set even though two values ship today, and fall back
to a plain link to src for a value you do not recognise, or when videoId
comes back null. Render nothing for a src of null.
divider
Carries no fields at all:
Rendering it
A minimal renderer is a switch with eight arms and a default:default arm. The eight types above are the whole set today, and a
type you do not recognise can only mean a block type added after your code was
written. Skipping it costs a reader one block; throwing costs them the article.
The two media arms hand src, alt and caption to your own components, which
is where the escaping rule above applies: build those nodes rather than
concatenating the fields into markup.
Render a club’s articles has the same
renderer written that way.
A short renderer that only wants its own media components is shorter still:
intercept image and video_embed, and pass everything else through as
block.html ?? "".
Where to go next
- Articles for the endpoints and their parameters.
- Render a club’s articles for a working page.