Insert HTML and Markdown

Convert, inspect, and apply bounded HTML or Markdown content to an open DOCX.

The Document API accepts HTML and Markdown as structured input. You can inspect the canonical fragment first, or pass the source directly to insert() or replace().

HTML and Markdown are not Word package fragments. SuperDoc preserves the supported structure listed below, normalizes representation details, and reports anything it drops or downgrades.

Convert before applying

Use htmlToFragment() or markdownToFragment() when your application needs to inspect diagnostics or reuse the canonical fragment:

import { SuperDoc } from 'superdoc';
import 'superdoc/style.css';

const superdoc = new SuperDoc({
  selector: '#editor',
  document: '/contract.docx',
  onReady: async ({ superdoc }) => {
    const doc = superdoc.activeEditor?.doc;
    if (!doc) throw new Error('The active document is unavailable.');

    const converted = await doc.htmlToFragment({
      html: '<h2>Scope</h2><p><strong>Review</strong> this clause.</p>',
    });
    const fatal = converted.diagnostics.find((diagnostic) => diagnostic.severity === 'error');
    if (fatal) throw new Error(`HTML conversion failed: ${fatal.message}`);

    const insertInput = {
      type: 'html',
      value: '<h2>Scope</h2><p><strong>Review</strong> this clause.</p>',
    } as const;
    const checked = await doc.capabilities.check({
      operation: 'insert',
      input: insertInput,
      options: { changeMode: 'tracked' },
    });
    if (checked.operation !== 'insert') {
      throw new Error(`Unexpected support-check operation: ${checked.operation}`);
    }
    if (!checked.supported || !checked.guard) {
      throw new Error(`Rich insert is not supported: ${checked.failure?.message ?? checked.outcome}`);
    }

    const insertReceipt = await doc.insert(insertInput, {
      changeMode: 'tracked',
      supportCheck: checked.guard,
    });
    if (!insertReceipt.success) {
      throw new Error(`Rich insert failed: ${insertReceipt.failure?.message ?? 'unknown failure'}`);
    }

    const match = await doc.query.match({
      select: { type: 'text', pattern: 'Existing clause' },
      require: 'exactlyOne',
    });
    const clause = match.items[0];
    if (!clause || clause.matchKind !== 'text') throw new Error('The clause was not found.');

    const replaceReceipt = await doc.replace(
      {
        target: clause.target,
        type: 'markdown',
        value: '**Replacement clause** with a [reference](https://example.com/policy).',
      },
      {
        changeMode: 'tracked',
        expectedRevision: match.evaluatedRevision,
      },
    );
    if (!replaceReceipt.success) {
      throw new Error(`Rich replace failed: ${replaceReceipt.failure?.message ?? 'unknown failure'}`);
    }

    console.log(checked.outcome, insertReceipt.outcome, replaceReceipt.conversion);
  },
});

window.addEventListener('beforeunload', () => {
  superdoc.destroy();
});

Each result contains:

  • fragment: the canonical structured content.
  • lossy: true when conversion normalized, downgraded, or dropped source content.
  • diagnostics: ordered, source-located conversion findings.

A warning-bearing result can still be applied. An error means there is no safe rich fragment to apply. Check diagnostic severity and disposition instead of treating every lossy result as a failure.

Check an exact workflow before applying

Use doc.capabilities() for a cheap synchronous snapshot of general operation availability. Use doc.capabilities.check() when the answer must account for exact HTML or Markdown, the current target, the requested change mode, and the current document revision. A check does not mutate package bytes, history, tracked changes, or the public revision.

A supported write that would change the document returns a guard. Pass it to the unchanged rich insert() or replace() request. The write fails closed when the source, format, target, placement, story, nesting policy, mode, analysis result, or document revision no longer matches. The guard digest detects accidental reuse; it is not a security signature.

The common outcome is preserved, preserved-with-warnings, simplified, rejected, no-op, invalid-target, or outdated. Read the complete conversion diagnostics and final mutation receipt before choosing application-specific fallback behavior.

Insert or replace raw source

Pass value with type: 'html' or type: 'markdown' to convert and apply in one call. Rich insert supports a selection, a block with before or after, a ref, or no target for append. Rich replace accepts a selection, paragraph or heading block, whole table block, ref, or the explicit { kind: 'story', storyType: 'body' } target.

The body target replaces all main-body blocks in one direct mutation while retaining the destination DOCX package and terminal section properties. It does not replace the DOCX file. Tracked mode is supported for selection and block workflows, but tracked whole-body replacement returns CAPABILITY_UNSUPPORTED.

Use dryRun: true to resolve and preflight without creating IDs, history, or document changes. Pair a mutation with expectedRevision when it depends on an earlier read.

Successful raw-source receipts include the final outcome and a conversion report. They may also include created entity identities, source-path effects, affected stories, text-range shifts, and a transaction ID. Check success before using any success-only field.

Supported inbound constructs

Source constructResult
Paragraphs, headings, bold, italic, underline, strike, hard breaksPreserved as canonical blocks and runs
Ordered and unordered lists, including bounded nesting and ordered startsPreserved with canonical list levels
Tables with a complete leading header row and column spansPreserved; explicit widths and broad table styling are not
Safe http, https, and mailto linksPreserved as external hyperlinks
Horizontal rulesPreserved as durable horizontal-rule blocks
Safe bounded color, font, spacing, indentation, cell shading, and paddingNormalized to typed canonical properties
Code, block quotes, task markers, and unsupported inline formsDowngraded or dropped with diagnostics
Scripts, event handlers, unsafe URLs, raw images, nested tables, row spans, malformed or over-limit inputSanitized with warnings when safe structure remains; otherwise rejected

The limits are deliberate. Arbitrary CSS, embedded active content, and full DOCX package fidelity are outside the HTML/Markdown contract.

Projection and persistence

Direct changes are immediately part of the document. This inbound API creates review markup that can be accepted or rejected through the tracked-changes API. Detailed outbound HTML and Markdown reads can then project redline, final, or original views. Save and reopen the DOCX before treating a mutation workflow as complete.

Standalone outbound conversion of an SDFragment to HTML or Markdown is not part of this inbound API. Document reads have a separate HTML and Markdown projection contract, including compact string getters and detailed reads with review, fidelity, and provenance metadata.

For target discovery, start with query content. For failure handling, see receipts and errors. The generated HTML conversion reference, insert reference, and replace reference list the complete shapes.

On this page