# The HTML dialect The HTML `adfToHtml` writes: semantic elements for the nodes and marks below, and the carry element for every other node (`docs/decisions.md` §The HTML dialect). The written form is contract (`docs/decisions.md` §The formats are API). ## Blocks One block a line: blocks are separated by a line feed, and a document holding any ends with one. A document whose `content` is an empty array is the empty string. | ADF | HTML | | --- | --- | | `paragraph` | `
…
` | | `heading`, `level` 1 to 6 | ``, a line feed, its blocks, a line feed, `` | | `bulletList` | `
` element where it holds an attribute, `
Bolt
…`, the language one token holding no ASCII whitespace (a tab, line feed, form feed, carriage return or space); no `class` where it holds no `language` |
| `rule` | ``. A code block's
`data-*` attributes stand on its ``.
## Inline
| ADF | HTML |
| --- | --- |
| `text` | its text, escaped |
| `em`, `strong`, `code` | ``, ``, `` around the text |
| `link`, holding `href` and an optional `title` | `` around the text |
| `hardBreak` | `
` |
A text node's marks nest in the order its `marks` array lists them, the first outermost:
`manual`. Each text node writes its own elements, so two text nodes a link
marks are two `` elements.
## Escaping
Text and attribute values escape `&`, `<`, `>` and `"` as `&`, `<`, `>` and `"`.
Attribute values are double-quoted. Every URL is written as the ADF holds it, whatever its scheme
(`docs/decisions.md` §HTML writes a URL as the ADF holds it, whatever its scheme): a link's `href`,
an image's `src`, and the `href` of each link a carry element shows.
HTML text and attribute values cannot hold a carriage return, which a parser reads as a line feed,
a control other than a tab, line feed or form feed, a noncharacter, or a lone surrogate, which
UTF-8 cannot encode (WHATWG HTML §13.1.3). A node holding one in a value its element writes rides
the carry.
## The carry element
A node the sections above cannot write where it stands is the carry element: `` in block
position, `` inline, of class `adf-carry`, holding the node's JSON in `data-adf` and showing
its content. A carry element may hold a node the sections above write, as the markdown carry may:
it reads back as the node it holds, so HTML stored while a node rode the carry reads the same once a
later release writes it as its own element.
```html
Read the CommonMark spec first.
Then import.
Ask @Mikael
```
- `data-adf` holds the node's JSON compact, keys sorted, as `!adf:carry` does in markdown, its type
included, each character HTML cannot hold spelled as a JSON escape, `\u0085`. A document holding
no `content` key is the block carry of `{"type":"doc","version":1}`.
- The content shown is every text node's text below the node, and what a node holding no text shows
in its place: a mention's text, else `@` and its id where it has one; an emoji's text, else its `shortName`; a
status's text; a date as `2026-09-13` in UTC; a card's URL, else its name, else the URL its data
holds; media's `alt`, else an external one's URL; an extension's text; an expand's title.
- In a ``, each block's content is a ``, and a code block's is
`
…
`, keeping its line feeds and spaces. Its class
is the one the code block's element takes, and it has none where the language is no class
token. In a ``, `
` parts two blocks'.
- A hard break is `
`, and so is a line feed in text outside a ``'s code block.
- Text a link marks is `` around it, and a card or an external image is a
link to its URL.
- An image a link to another target marks shows as portable markdown writes it inline, the link
around its `alt`, else the link's target, else its URL, then `image` linking to the image in
parentheses: `The moon (image)`.
- A node referencing what it cannot show is a note naming it, `(image)`: `image` for
media with no `alt` or URL, `link card` for a card with neither URL nor name, an extension's
key, else `extension`, for an extension with no text, and `synced block` for a `syncBlock`. A
link marking the node goes around the note: `(image)`.
- Characters HTML cannot hold are dropped.
- A node rides the carry where it holds a mark or a key its element does not write, an attribute
its type does not hold as that kind, an empty `attrs`, `content` or `marks`, or a value its
element cannot hold:
- text holding no character, or a character HTML cannot hold; text holding a mark twice, or a
mark with attributes besides a link's `href` and `title`;
- an unmarked text node straight after another, which would read back as one;
- a link whose `href` or `title` holds a character HTML cannot hold, and an image whose `url` or
`alt` holds one or whose link's `href` or `title` does;
- an image holding an attribute besides its `center` layout and its media's `type`, `url` and
non-empty `alt`;
- a heading whose `level` is not 1 to 6, and an ordered list whose `order` is not a safe integer
or is `-0`;
- a code block holding more than one text node, a marked one, or a language holding ASCII whitespace;
- a rule or hard break holding `content`, and a hard break holding an attribute;
- a list holding a node that is no `listItem`, or an item holding a mark, text, an empty key or
an attribute its type does not hold: the whole list rides the carry;
- a `listItem` outside a list, an inline node in block position and a block node inline.
- A block carry's JSON nests at most 500 levels less the depth it stands at, an inline carry's at
most 500, as in markdown.