@eigenpal/docx-editor-core
Framework-agnostic core: document tree, OOXML parser/serializer, ProseMirror schema, plugin contract. Underlies both the React and Vue adapters.
What's in it
The document tree, the OOXML parser and serializer, the ProseMirror schema, layout primitives, the plugin contract. No DOM, no framework. The React and Vue adapters depend on it. You install -core directly only when you don't want an editor UI on the page.
npm install @eigenpal/docx-editor-coreWhen to use it directly
- Server-side
.docxprocessing: parse buffer, walk the tree, mutate, serialize back out. - Headless extraction: pull text, tables, headers/footers without rendering.
- Custom renderer or DOM bridge against the shared schema.
- Plugins that need to work in React, Vue, and headless contexts. Use the
core-pluginssubpath.
If you want an actual editor in a React or Vue app, install @eigenpal/docx-editor-react or @eigenpal/docx-editor-vue. Both pull -core in transitively, so you don't need it as a separate dep.
Subpaths
61 published subpaths. The ones you'll touch most:
@eigenpal/docx-editor-core: root barrel@eigenpal/docx-editor-core/docx-parser:parseDocx(buffer)→Documenttree@eigenpal/docx-editor-core/docx-serializer:Document→.docxbuffer@eigenpal/docx-editor-core/types:Document,Paragraph,Run,Insertion,Deletion,Comment@eigenpal/docx-editor-core/core-plugins: plugin contract for non-React, non-Vue hosts@eigenpal/docx-editor-core/headless: bridge-shaped APIs (no DOM)
All 61 are in the API reference.
Parse, mutate, serialize
import { parseDocx } from "@eigenpal/docx-editor-core/docx-parser";
import { serializeDocx } from "@eigenpal/docx-editor-core/docx-serializer";
const buffer = await fetch("./document.docx").then((r) => r.arrayBuffer());
const tree = await parseDocx(buffer);
for (const para of tree.body) {
if (para.type === "paragraph") {
console.log(para.paraId, para.runs.map((r) => r.text).join(""));
}
}
const out = await serializeDocx(tree);The tree shape is the same the editor renders against. Anything you build against -core ports without translation when the same buffer reaches the live editor.
Content controls
Block-level content controls (Word's w:sdt) are addressable by tag, alias, id, or type. findContentControls lists the matches and findContentControl returns one; each carries its text plus modeled state (showingPlaceholder, checked, dateFormat, listItems, dataBinding). setContentControlContent fills a control with a string or block content, setContentControlValue sets a typed value (dropdown selection, checkbox, date), and removeContentControl deletes or unwraps one.
import { findContentControls, setContentControlValue } from "@eigenpal/docx-editor-core/headless";
const boxes = findContentControls(tree, { type: "checkbox" });
setContentControlValue(tree, { tag: "agreed" }, true);Edits preserve the control's identity and raw properties, so the document still round-trips. Locked and typed controls are refused unless you force them. That stability is what makes content controls usable as anchors for templates and document automation. Repeating sections (w15:repeatingSection) round-trip the same way: addRepeatingSectionItem clones an item with fresh ids and removeRepeatingSectionItem drops one.
Where to next
- API reference (61 subpaths)
- Plugins for the plugin contract
@eigenpal/docx-editor-agents:DocxReviewerwraps-corefor AI-driven document review