Editor Integration
SuperDocs identifies every block-level element in your document with adata-chunk-id attribute. Your editor must preserve those attributes across the round-trip — HTML in, editor model, HTML back out — for surgical edits to work.
This guide covers attribute preservation in a rich-text editor. For rendering inline diff overlays inside the editor, see Human-in-the-Loop → Rendering diffs inline in your editor. For streaming events, see SSE Streaming. If your product doesn’t have an editor — your AI agent is the consumer of SuperDocs, or you’re running server-side / batch — see Agent Tool Integration or Server Integration instead.
Why this matters
Every SuperDocs response returns HTML like this:data-chunk-id values are how the AI references specific sections when it proposes edits. When your app sends the document back on the next turn, those same IDs must still be on the same blocks. If they aren’t, the AI’s “edit Section 2” request lands on the wrong block — or nothing at all.
The failure mode is silent. Most rich-text editors strip unknown HTML attributes by default when parsing input into their internal model, and/or don’t emit them when serialising back to HTML. Edits work intermittently on blocks whose tags happen to survive, and fail mysteriously on the rest. No error is thrown. A five-minute check now saves hours of debugging later.
The pattern, in plain English
Every editor integration follows the same three steps:- Parse incoming HTML from SuperDocs into your editor’s document model, preserving
data-chunk-idon every block-level node. - Serialise the editor model back to HTML, preserving the same
data-chunk-idattributes. - Render incoming
final.updated_htmlanddocument_sync.contentpayloads by re-running step 1 against the new HTML.
Working snippets
- ProseMirror
- TipTap
- Slate
- Lexical
- Quill
- CKEditor 5
Install the vanilla ProseMirror packages:Your schema needs to do two things:Use this
- Add
data-chunk-idas a preserved attribute on every standard block node (paragraph, heading, list, blockquote, code block, horizontal rule). - Register a wrapper node for
<div data-chunk-id="…">…</div>elements. SuperDocs uses these wrappers when a single chunk spans multiple block elements (e.g. a heading plus the paragraphs that follow it). If your schema has no node that matchesdiv[data-chunk-id], the parser will descend into the children, the wrapper’sdata-chunk-idwill be silently dropped, and any inline-diff or chunk-targeted edit referencing that ID will fail to render. The basic ProseMirror schema does not include a<div>node — you must add one.
schema when creating your EditorState. Use DOMParser.fromSchema(schema).parse(htmlElement) to load SuperDocs HTML and DOMSerializer.fromSchema(schema).serializeFragment(doc.content) to serialise it back out.Where this slots in: typically inside a React / Vue / Svelte component that mounts ProseMirror via new EditorView(domNode, { state }). Expose two methods on a ref — getHtml() and setHtml(html) — so the chat panel can read the current document before each send and write the updated HTML after each final event.Other editors and custom implementations
The principle is the same regardless of editor: preserve unknown HTML attributes on block-level elements across parse and serialise. Three things to verify in your editor’s documentation:- Does the parser strip unknown attributes by default? Most do. Look for “custom attributes” or “attribute preservation” in the docs.
- Does the serialiser emit them when converting back to HTML? If the parser accepted them, the serialiser usually does — but not always.
- Does the internal model store them on every block type you plan to use? Often there’s a schema or node definition that has to be extended per node type.
Verification test
Paste any SuperDocs response into your editor, read the HTML back out, and diff against the input. Everydata-chunk-id must survive.

