NavShell, Hero, Form, Table, and the rest. By the end of this page you will know what a block is, how blocks compose into a complete page, and where to look up the props for any individual block.
The point of the design: every page is data, not code. You can GET a page, edit the JSON, and PATCH it back — no build step, no deploy. The runtime takes the document and renders it: server-rendered HTML on first load, then a WebAssembly bundle in the browser for interactivity.
A first example
Here is a complete page document — a marketing landing page with navigation, a hero, a feature grid, and a footer:landing.json
version pins the document schema revision so the runtime knows how to interpret the fields. metadata carries the URL slug and HTML title. tree is a single root block (NavShell) wrapping the page’s sections as children. Each child names a block type, carries its configuration in props, and may itself contain further nested blocks.
The mental model
Think of a block as a named, typed UI primitive. The name says what kind of section it is (Hero, Form). The props are its configuration (headline, cta_href, schema_table). The tree is the page.
Two properties fall out of this shape. Pages are portable — the same JSON renders the same page in any workspace running the same runtime version. And pages are AI-friendly — a language model can read the tree, propose a JSON Patch, and round-trip an edit reliably, which is why the Builder MCP exposes block schemas as introspection tools.
The analogy has a limit. Blocks are not React components you can write inline — you cannot ship a custom block type by dropping a .tsx file in your repo. The block catalogue is closed; new types ship with the runtime. What you customize is the composition and the props.
The ten block types
The first six are presentational — pure layout with no data binding. The last four are data-bound — they read or write rows in a schema table you declare on the page document.Beyond the core ten
The ten blocks above cover the structural skeleton of a page. The runtime ships a broader palette of section and interactive blocks that you compose as children inside the structural ones. They share the same JSON shape —block, props, children — and the same theming, visibility, and analytics props.
Marketing sections are presentational blocks meant for landing-page content above and below the structural shell. The catalogue covers the layouts you reach for when describing a product: an alternating features section, a card-style bento grid, a callout band, a comparison table, an FAQ accordion, a logo cloud, a pricing table, a pull quote, a stats row, a testimonials carousel, and a newsletter sign-up. Each one is a typed block with its own props — you do not stitch them out of raw HTML.
Interactive blocks are data-bound surfaces tuned for end-user-facing apps that go beyond a basic list-and-detail view. The catalogue includes a calendar view for date-indexed records, an intake form tuned for multi-step lead capture, and a card-style list view variant for record browsing where the table block would feel heavy.
Both families render through the same pipeline as the core ten: server-side HTML on first load, then a WebAssembly bundle in the browser for interactivity. A page that mixes a Hero, a marketing Pricing section, and a data-bound Calendar view is a single document, not three.
Common props
Every block accepts these four optional props in addition to its own type-specific ones.How blocks pick up the theme
Every visual property a block exposes — color, spacing, type scale, corner radius — resolves through workspace theme tokens, not hard-coded values. Change one token and every block instance picks up the new value on the next render. When you need a one-off tweak on a single block, useclass_overrides on that instance — it layers on top of the resolved token values and does not affect any other block. See Theme for the full token model.