Getting started
Install the package, mount the editor, and export the edited document.
Install the package
npm i @portone/docx-editorImport the stylesheet
import "@portone/docx-editor/styles.css";Once per application; it includes the ProseMirror base styles. Styling covers the custom properties that restyle the frame.
Get a document to open
document takes a File, a Blob, an ArrayBuffer, or a Uint8Array:
const response = await fetch("/agreement.docx");
const file = new File([await response.blob()], "agreement.docx");Mount the editor
import { DocxEditor, type DocxEditorHandle } from "@portone/docx-editor";
import { useRef } from "react";
export function Editor({ file }: { file: File }) {
const editorRef = useRef<DocxEditorHandle | null>(null);
return (
<DocxEditor
ref={editorRef}
document={file}
mode={{ kind: "edit", author: { id: user.id, name: user.name } }}
/>
);
}mode is a reader's, a commenter's, or an editor's surface, and author is the signed-in user
comments are written under; Props describes the prop and
Modes what each kind lets a person do.
The editor fills the height it is given, so put it in a box with one.
Export the edited document
downloadDocx takes the handle from the ref and saves the current state as a file:
import { downloadDocx } from "@portone/docx-editor";
const download = () => {
const result = downloadDocx(editorRef.current, { fileName: file.name });
if (result.status === "blocked") {
console.warn(result.problems.map((problem) => problem.code));
}
};
<button onClick={download} type="button">
Export .docx
</button>;It reports unavailable while no document is open, empty when there is nothing to export, and
blocked with the problems when the document cannot be written back safely.
For the bytes without a download, call editorRef.current.exportBytes(); for the problems ahead
of it, editorRef.current.exportProblems().
Check what you see
An opened document shows its own paper, fonts, and styles, with page boundaries drawn over the
text and the toolbar above it.
If a panel naming a reason appears instead, the document was refused; pass renderImportError to
render the refusal yourself, and Errors lists the codes.
Exporting and reopening the file in Word is the real check.
Next.js and other prerendering frameworks
The editor cannot render on the server, so load it from a client component through a dynamic import with server rendering turned off:
"use client";
import dynamic from "next/dynamic";
const Editor = dynamic(() => import("./Editor").then((m) => m.Editor), {
ssr: false,
});Fetch the document inside that client component too.
The App Router also needs @portone/docx-editor in transpilePackages when it resolves to
TypeScript sources, as a workspace link does.