

## Overview [#overview]

`Editor.Root` has one content API for every supported format:

```tsx
<Editor.Root
  content={content}
  contentFormat="blocknote"
  onContentChange={({ content }) => saveContent(content)}
>
  <Editor.View />
</Editor.Root>
```

Set `contentFormat` to choose the canonical type Cubitt receives and emits.
Consumers do not need separate props for Markdown and BlockNote JSON.

## BlockNote JSON [#blocknote-json]

Use `contentFormat="blocknote"` when the consuming app can persist BlockNote
blocks directly. This is the richest mode and supports the full free BlockNote
editing surface, including toggle blocks, file/media blocks, tables, slash
commands, drag handles, side menu, and table handles.

```tsx
<Editor.Root
  content={blocks}
  contentFormat="blocknote"
  onContentChange={({ content }) => saveBlocks(content)}
  uploadFile={uploadFile}
>
  <Editor.View />
</Editor.Root>
```

In this mode, `content` is `EditorPartialBlock[]`, and `onContentChange`
emits `EditorPartialBlock[]`.

## Markdown [#markdown]

Use `contentFormat="markdown"` when the consuming app stores Markdown as the
source of truth.

```tsx
<Editor.Root
  content={markdown}
  contentFormat="markdown"
  onContentChange={({ content }) => saveMarkdown(content)}
>
  <Editor.View />
</Editor.Root>
```

In this mode, `content` is a string, and `onContentChange` emits a Markdown
string.

Markdown mode intentionally narrows the editor UI to blocks and inline content
that can round-trip through BlockNote's Markdown parser and exporter. It does
not expose `uploadFile` or `resolveFileUrl` because dedicated BlockNote file
and media blocks are not native Markdown content.

<Preview name="EditorMarkdownExample" />

## Supported Blocks [#supported-blocks]

BlockNote mode supports the default free BlockNote block set:

| Block            | BlockNote JSON | Markdown              |
| ---------------- | -------------- | --------------------- |
| Paragraph        | Yes            | Yes                   |
| Heading 1-6      | Yes            | Yes                   |
| Quote            | Yes            | Yes                   |
| Bullet list      | Yes            | Yes                   |
| Numbered list    | Yes            | Yes                   |
| Checklist        | Yes            | Yes                   |
| Code block       | Yes            | Yes                   |
| Table            | Yes            | Yes                   |
| Divider          | Yes            | Yes                   |
| Image            | Yes            | Markdown image syntax |
| File             | Yes            | Markdown link only    |
| Video            | Yes            | Markdown link only    |
| Audio            | Yes            | Markdown link only    |
| Toggle heading   | Yes            | No                    |
| Toggle list item | Yes            | No                    |

Markdown can preserve file, video, and audio references as links, but those
links are not the same as BlockNote's dedicated file/media blocks. If an app
needs first-class uploads, previews, captions, and file panels, persist
BlockNote JSON.

## Controlled Content [#controlled-content]

Use `content` for controlled content. This is the right path for reactive data
sources such as TanStack DB query results.

```tsx
<Editor.Root
  content={markdown}
  contentFormat="markdown"
  onContentChange={({ content }) => setMarkdown(content)}
>
  <Editor.View />
</Editor.Root>
```

`contentFormat` determines the type for all content props and change events.
