A close-up portrait of a man with a salt-and-pepper beard wearing a white collared shirt against a textured beige background.
A close-up portrait of a man with a salt-and-pepper beard wearing a white collared shirt against a textured beige background.

Everything the page editor also builds

Jesse James Richard
|
Jan 12, 2026
|
9 min read
#Architecture
#AI & Agents

Yesterday I wrote about the page editor and the typed tree underneath it. The useful thing about that tree is what it is not. It is not a page. A page is one way of rendering it.

So the question stops being how do I build a page editor and becomes what else is a tree of sections and blocks. Over the past few weeks the answer has been most of what a marketing site is made of. Pages and posts. Headers and footers. Sidebars. The templates that arrange them. Dialogs. Forms. And email, which fights back.

None of those needed a second editor. Each one is the same tree in a different table, with a palette offering the blocks that make sense there. A help centre and a documentation site are the same shape again, and I expect they arrive the same way when I get to them.

Three kinds of tree

They divide into three groups, and what separates them is small.

Content someone reads. A page, a post, an email. These have a lifecycle. They are drafted, published, sometimes scheduled. Someone arrives at one of them deliberately.

Chrome that wraps content. A header, a footer, a sidebar, a dialog, and the template that positions them. Nobody navigates to a header. It is always live, there is no draft of it, and changing it changes every page it wraps.

Forms. A form is a tree of blocks like everything else, except its blocks collect input instead of displaying it. A text field is a block. A select is a block. The submit button is a block. Laying out a form uses the same canvas and the same drag targets as laying out a page.

What differs between the three: which table the row lands in, whether the type has a published state, and which blocks the palette offers. Everything else is the same code, not merely the same approach. One tree shape, one set of drag interactions, one undo stack.

The console with the pages list open, and a left-hand menu listing landing page, pages, posts, layouts, headers, footers, sidebars, dialogs and forms.
The menu on the left, not the table. Landing page, pages, posts, layouts, headers, footers, sidebars, dialogs, forms. One editor behind every one of them.

A block that renders nothing

A template has to contain a page it does not know about, which is the one thing in the tree that could not be solved by another block type.

It was solved by another block type. A template is an ordinary tree, edited in the ordinary canvas, except four of the block types available in it render nothing at all. One says the header goes here. One says the footer goes here. One says a sidebar goes here, and how wide. And one says this is where the body goes, whatever the body turns out to be.

A template is a skeleton with slots

Template tree                Assembled page
section  header marker       ──►    the header's sectionssection  sidebar marker  ┐  body marker     ┘   ──►    sidebar beside the page's sectionssection  footer marker       ──►    the footer's sections
A template open in the builder canvas showing three marker blocks stacked: a header marker, a body marker labelled where the page content will appear, and a footer marker.
A template in the canvas. Header, body and footer markers, each one a block you can drag.

At render time the server walks the template, swaps each marker for the tree it points at, and hands the result to the renderer as one flat set of sections. The renderer never learns that a template existed. It receives a page and draws it.

A person editing a template drags those markers around like any other block. Putting the sidebar on the left means dragging the sidebar marker before the body marker. There is no template editor, no template language, and nothing new to learn.

Email, the hard one

Most of those surfaces render the way a page does: HTML, in a browser, which is forgiving. Email does not.

An email is a hostile target. Tables inside tables, a decade of client quirks, no reliable stylesheet, rules that were old when the browser was young. A page and an email are different engines with a different set of things that work.

A button is still a button in both places, with the same options. The person who placed it thought about a button, not about either rendering. Here it is on its way to the inbox:

The button block, rendered to MJML

<mj-button href="/signup" background-color="#ff5722"  border-radius="8px" align="center">Start free</mj-button>

Email gets its own block types, which is the one place the model breaks down. An email heading and a page heading are separate definitions, because the constraints are different enough that a single block would render badly in both places. The vocabulary is shared, the code is not. When the page button gained an outline variant and a border radius, the email button gained them too, and the compiler learned to express them in a way a mail client would honour.

Every surface relates to the palette the same way. A block declares which contexts it belongs to, and the palette is that registry filtered. The email palette and the page palette are two views of one library. A form field never appears while you are laying out a header, and nobody maintains a second list to make that true.

Website
Email

Engine

HTML, taken by the browser

MJML, compiled to nested tables

One button becomes

A styled element

A table cell

Environment

Modern, forgiving

A decade of client quirks

variant, size, radius, alignment

Why two systems drift

The usual shape of a marketing stack is five products. A website builder, an email template tool, a form builder, a help centre with its own editor, a docs site with a third. Five ideas of what a button is, five places the brand colour is configured.

They start close and come apart. The brand colour changes, the site updates, the email is a season behind. The logo is replaced everywhere except the footer of the newsletter. Nobody decides that the email should look older than the site; it happens because keeping five systems aligned is manual work that nobody is assigned.

With one model there is no alignment step. The brand is a set of values the blocks read, defined once, and a change to it lands on every surface at the same moment because nothing had to be copied anywhere.

Why a model needs structure

The same property serves a second reader. A page of markup lets anything sit anywhere, so working out what it means requires parsing it and guessing. A tree of blocks is typed: a button with its options, a heading with its level, a divider with its style.

For a person that is a convenience. For a model it changes the job. An AI given raw HTML is reasoning about presentation, tags and styles and nesting, hunting for the content inside it. An AI given blocks receives the content already separated from its rendering, in named fields with known limits, and can only fill those fields. That constraint is what brand voice needs. Freeform text cannot be held steady. A structure that permits a fixed set of moves can.

That is the bet under the block model, and the platform made the same bet once already by feeding its AI structured events rather than raw logs. Today it keeps a website and an email in agreement. Later it should let a machine generate content without losing the voice, because the voice will be enforced by the structure rather than left to the prose.

Define it once

I set out to build a page editor. What I have is an editor for anything a business puts in front of someone, because once the content is a typed tree, the surface it renders to is a detail rather than a product.

That was not foresight. I wanted Elementor without WordPress and I built the tree because the tree was the right way to build the editor. Everything since has been discovering how much else was already a tree. A header. A form. An email. Each one arrived as a table and a palette rather than a project, and the next ones will too.

If it transfers anywhere else, it transfers as this: model the subject once as structure, and treat every surface as a rendering of it. The same instinct as writing the architecture before the product. Adding the next surface then costs whatever it costs to render that tree one more way, which is a week rather than a quarter.

The block editor came before the AI

#Signature
#Architecture

Giant Context is being built as an AI that makes websites, and none of that comes first. What comes first is a page editor a person uses with no model...

Jesse James Richard

|

Jan 11, 2026
Read previous

Building something like this

I'm Jesse. I build platforms end to end, and I'm open to work. If this is the kind of engineering you need, get in touch.

Contact Jesse
Home
About
Contact
Sitemap
Privacy Policy
Terms of Service
Cookie Policy
Everything the page editor also builds | Jesse James Richard