# Rich text (/docs/api/rich-text)

Rich text fields are ProseMirror-style JSON documents, with TipTap's node and mark names. The entry editor writes exactly this format, and the delivery API answers it by default.

```json
{
	"type": "doc",
	"content": [
		{
			"type": "heading",
			"attrs": { "level": 2 },
			"content": [{ "type": "text", "text": "Intro" }]
		},
		{
			"type": "paragraph",
			"content": [
				{ "type": "text", "text": "Some " },
				{ "type": "text", "text": "bold", "marks": [{ "type": "bold" }] }
			]
		},
		{
			"type": "embeddedAsset",
			"attrs": { "id": "asset_…", "asset": { "url": "…", "alt": "…" } }
		}
	]
}
```

- **Nodes**: `paragraph`, `heading` (`level`), `blockquote`, `bulletList`, `orderedList` (`start`), `listItem`, `codeBlock` (`language`), `horizontalRule`, `hardBreak`, `text`, `embeddedEntry`, `embeddedAsset`.
- **Marks**: `bold`, `italic`, `underline`, `strike`, `code`, `link` (`href`, `target`, `title`).

## Embeds [#embeds]

Embedded entries and assets are stored by id and checked like references. In delivery responses they are resolved into `attrs.entry` / `attrs.asset`, following `depth`; ones that can't be resolved (unpublished, deleted) are left out.

## Writing it as Markdown [#writing-it-as-markdown]

The agent API and MCP accept Markdown for a rich text field, and store it as a document; prompt editing reads and writes rich text as Markdown too. Embed an asset with `![alt text](asset:asset_…)` and an entry with `![](entry:entry_…)`.

## As HTML [#as-html]

With `?richtext=html` the delivery API answers each rich text field as an HTML string instead:

- images as `<figure><img></figure>`, other files as links;
- embedded entries as `<div data-entry-id="…" data-content-type="…"></div>`, for the site to fill;
- links only ever have safe URLs (`http(s):`, `mailto:`, `tel:`, `#` and paths): others are refused when content is saved.

## Rendering it [#rendering-it]

- React: `<RichText document={…} />` from the [React SDK](/docs/sdk/react#rich-text), with your own components per node, mark or embed.
- Anything else: `richTextToHtml(doc, { renderEntry, renderAsset })` and `richTextToPlainText(doc)` from the [JavaScript SDK](/docs/sdk/javascript#helpers).
