Core

@docx-editor.dev/core

The framework-agnostic engine: OOXML read and write, the canonical document tree, layout, paint, and the Editor contract that adapters render.

The engine. It reads a .docx into a canonical document tree, lays that tree out into pages, paints them, and writes the tree back to OOXML. It has no framework dependency and no UI.

Most apps never import it directly: @docx-editor.dev/react carries it. Reach for it when you are writing your own adapter, or when you need the contract types to type a function signature.

npm install @docx-editor.dev/core

Entry points

The root is the entry point for most work: create an editor over bytes, the contract it implements, fonts, and the chrome registry.

import { createDocxEditor, loadFonts, WORD_DEFAULT_FONT } from '@docx-editor.dev/core';
import type { Editor, EditorSnapshot } from '@docx-editor.dev/core';

Reach for a subpath when you need the canonical tree, the layout pass, or the paint step directly.

SubpathWhat's there
.Create an editor, the Editor contract, fonts, the chrome registry, the document model types.
./editorEverything the root re-exports, plus the paginated surface, ruler geometry, and module resolution.
./contracts/editorEditor, EditorCommand, EditorQuery, EditorSnapshot, DocumentSource, PageSetup, the contract an adapter renders.
./contracts/documentThe document-level edit and query vocabulary.
./contracts/typesDocument model types.
./contracts/modulesEditorModule, the shape @docx-editor.dev/pro implements.
./contracts/interactionSemantic addressing (SemanticTarget) and the InteractionOutcome an attempt answers with.
./storeThe canonical tree and its transactional store.
./layoutThe DOM-free layout pass.
./outputPaint: turning a laid-out document into page DOM, and the selection overlay over it.
./automationThe document object model behind @docx-editor.dev/editor-api.
./styles/editor.cssThe one editor stylesheet. The packaged chrome and your own chrome both use it.

Root or ./editor? Import from the root. ./editor is the same engine with its internals attached (the paginated surface, ruler geometry, module resolution), and you want those only when you are building an adapter rather than using one.

The contract

Editor is the whole public surface an adapter talks to. Commands go in through exec, reads come out through query and snapshot:

import type { Editor, EditorSnapshot } from '@docx-editor.dev/core/contracts/editor';

function pageLabel(editor: Editor): string {
  const snapshot: EditorSnapshot = editor.snapshot();
  return `${snapshot.page.current} / ${snapshot.page.total}`;
}

snapshot() is version-cached: it returns the same reference until state actually moves, and its sub-objects are reference-stable. That is what makes useSyncExternalStore (and therefore useEditorState) correct without a deep compare on every tick.

The pipeline

One path, in one direction:

bytes → bounded OPC/XML read → canonical document tree → layout → painted pages → serialize

The painted pages are the editable surface. There is no shadow document model to keep in sync with what you see.

Fidelity is structural. The canonical tree preserves XML content and package payloads pass through untouched. Content the engine cannot type (an unknown element, or a known one in an invalid position) becomes a generic node rather than being dropped, so unknown content never blocks editing and never disappears on save.

Untrusted input

A .docx is a zip of XML that whoever sent it controls end to end. The engine sanitizes at the parse boundary (URL allowlisting, entity and zip-bomb limits, recursion and element caps, no zero-click external fetches, escaping on the way back out) so everything downstream receives an already-sanitized projection.

Anything you then render from document data (a font name, a hyperlink target, a comment body, a custom node's attributes) is still attacker-controlled at your boundary. Render it as text; do not build markup or URLs from it.

Next steps

  • Architecture: how the pipeline fits together
  • React: the adapter that renders this contract
  • Editing API: the object model over ./automation

On this page