docx-editor

Core API

Programmatic DOCX import and export without mounting an editor.

@portone/docx-editor/core provides programmatic DOCX import and export without mounting an editor. It returns a ProseMirror document together with an opaque session that retains the rest of the DOCX package.

Import and export

Keep the session returned by importDocx and pass it back to exportDocx with the original or transformed document:

import { exportDocx, importDocx } from "@portone/docx-editor/core";

const { doc, session } = importDocx(source);
const bytes = exportDocx(doc, session);

The core functions accept an ArrayBuffer or Uint8Array. The React component also accepts a Blob or File and reads it before import.

The session belongs to the imported document and must not be constructed or modified by consumers. Use documentNumbering(session) and documentPartPath(session) for the package information exposed by the public API.

Server environments

Browsers provide the DOMParser and Node globals used during import. A server must install compatible implementations before calling importDocx:

import { JSDOM } from "jsdom";

const { window } = new JSDOM();
globalThis.DOMParser = window.DOMParser;
globalThis.Node = window.Node;

Use a parser configuration that disables external entities and external fetching.

This works without friction on a long-running Node server. On serverless functions jsdom adds noticeable bundle weight and cold-start time, and edge runtimes cannot run it at all, so treat those environments as unsupported for now.

Errors

DocxImportError and DocxExportError expose stable code values for application handling. Error messages are intended for developers and may be reworded.

import { DocxImportError, importDocx } from "@portone/docx-editor/core";

try {
  importDocx(source);
} catch (error) {
  if (error instanceof DocxImportError) {
    console.error(error.code);
  }
  throw error;
}

Both classes are exported from the root entry as well, so a React screen can switch on the same codes without importing the core entry.

Import codes

CodeWhy the document was refused
not-a-docxThe bytes are not a readable zip container, its entry names are not a package's, or an entry does not hold what it claims to.
too-largeThe package asks to inflate beyond the limits below.
missing-partThe package carries no main document part.
missing-bodyThe main part carries no body.
malformed-xmlThe XML cannot be parsed, declares a DTD, or its markup is inconsistent.
unsupported-contentThe document holds markup that could not be written back out unchanged.

A file a person picked can fail with any of these, so the code is worth showing: not-a-docx and too-large are usually the person's to fix, while the rest describe the file itself.

Export codes

CodeWhy the document could not be written
missing-numbering-partA new list needs a numbering part the document does not have.
missing-content-typesA new image needs a content types part the package does not have.
unsupported-contentThe document holds a node kind with no way to serialize it.
lost-originalA node that carries only its original XML has lost it.
malformed-xmlAn original XML fragment cannot be read well enough to rewrite.
invalid-tableThe table grid is inconsistent, such as a vertical merge outliving its rows.

An export failure leaves the editor state untouched, so a screen can report the reason and let the person carry on editing. missing-numbering-part is the one an ordinary edit can reach: a document with no numbering part cannot take a new list, and the built-in list controls report that they do not apply for exactly that reason.

In the React component

The component renders a refusal in place of the editor when import fails, either through renderImportError or through the built-in panel, which turns each import code into a sentence. Only DocxImportError becomes a rendered refusal; anything else, a Blob that could not be read included, is thrown for an error boundary above to take. On the way out, downloadDocx and exportBytes rethrow DocxExportError as it is.

Import limits

  • A single inflated part is limited to 32 MiB and the package total to 64 MiB.
  • Package paths that escape the archive and XML containing a DTD are rejected.
  • An image over 16 MiB is retained in the package without being rendered by the editor.

Utilities

The core entry exports the document schema (docxSchema), the numbering reader (parseNumbering), typed format readers such as toRunFormat and toParagraphFormat, and the unit conversions emuToPx and pxToEmu used for programmatic transforms. The published TypeScript declarations describe the complete surface.

On this page