Attributes
Blocks and marks carry a fixed vocabulary of attributes — plus one escape
hatch, data. The vocabulary is closed by design: the model stays predictable,
and every adapter knows exactly what it must round-trip. Attribute persistence is
tiered — some attributes survive only in syntaxes that can store them.
The vocabulary
| Attribute | On | Description |
|---|---|---|
id |
any block | Link-target id; persisted only when targeted or pinned (see Links). |
src, alt |
void (media) blocks | Media source (a reference, never bytes) and accessible description. |
type |
void (media) blocks | Explicit media type (MIME); usually inferred from the src extension. |
width, height |
void (media) blocks | Intrinsic dimensions in CSS px (integers) — a content fact; presentation sizing stays in style. |
poster |
video blocks | Poster frame (the src reference grammar). |
controls, loop, muted |
audio/video blocks | Playback flags. controls defaults true; the others false. |
narration |
any block | { src?, start, end } — a narration clip: this block’s slice of the work’s narration audio, in seconds. src defaults to meta.narration. |
list |
text blocks | { type: "ordered" | "unordered", depth? } — list metadata. |
grid |
grid blocks | { headerRows?, headerCols? } — the leading N rows / first N cells render as <th> (a11y + Markdown table headers). |
colspan, rowspan |
grid cells | Cell spans. |
href |
marks | Link target — an external URL or an internal ref. |
rt |
marks | Ruby annotation text (rendered <rt> inside a ruby mark; adapters without ruby may render it parenthesized or drop it). |
title |
marks | A link title ([text](href "title") ↔ <a title>) — CommonMark parity. |
lang |
any block | Language override (BCP-47). |
dir |
any block | Direction override — "ltr" or "rtl". |
origin |
any block (in translation documents) | A block ref (^id) into the original this block translates — the alignment anchor. |
originRev |
any block (in translation documents) | The origin block’s revision marker when last aligned — staleness tracking. |
rev |
any block or mark | A revision id (config.revisions[].id) — “touched in this pass.” On ins / del marks it yields full tracked changes. |
data |
any block or mark | Custom escape hatch — a free { key: value } map. |
Attributes split by where they live:
BlockAttrs = { id?, src?, alt?, type?, width?, height?, poster?,
controls?, loop?, muted?, narration?,
list?, grid?, lang?, dir?, origin?, originRev?, rev?, data? }
MarkAttrs = { href?, rt?, title?, rev?, data? }
An inline image carries its
src / alt on the run’s object, not in an attribute bag — MarkAttrs
stays media-free.
A MarkUse is a bare id when it carries no attributes, and the object form
{ id, attrs } when it does — see runs.
Tiered persistence
Content and kind round-trip losslessly through every syntax. Attributes do not — a round-trip preserves content and kind, but not necessarily every attribute:
data,rev, and on-demandids persist only in syntaxes that can store attributes — HTML (data-*, nativeid,data-rev), FDX (natively), JSON (trivially).- The media attributes follow the same
tiers — full in html/json,
src/altonly in Markdown, alt-text-or-nothing in the plain-text syntaxes. The full table is on the Media page. - Content-derived syntaxes (plain text, Fountain, most of Markdown) have nowhere to put an attribute without polluting the text, so they simply don’t carry it.
This is a deliberate trade: the price of a plain-text or Fountain file that stays readable and editable in any tool is that it can’t silently smuggle metadata. The things a reader actually sees — the words and their block kinds — always survive.
A note on origin vs src
Both are block attributes and both look like references, but they are unrelated:
srcis a media source, on avoidmedia block.originis a translation alignment anchor, on a block in a translation document — a block ref into the original.
origin / originRev were renamed from an earlier src / srcRev precisely to
remove that collision. See Translations.