@docx-editor.dev/editor-api
v2.16.0 · 2 published subpaths with full TypeScript signatures and JSDoc.
Live agent demo
Describe a document. The agent drafts it through the live editor API, then proposes later edits as tracked changes. For the walkthrough, see Build a DOCX agent.
Subpaths
Package root
Work is described against proxy objects and nothing reaches the document until context.sync(), which sends one ordered batch and either applies all of it or none of it. Reading a property nobody asked for is an error rather than a silent undefined.
This entry needs no browser. It opens DOCX bytes, drives them, and saves them back, so a server, a worker or a build script can import the package name and get the whole API.
Functions (1)
isDocxEditorErrorfunctionSource ↗
Whether a caught value is one of ours.
By name as well as by instanceof: a consumer can end up with two copies of this module (a bundle plus a dependency's), and an instanceof that fails across them would send a perfectly ordinary PropertyNotLoaded down a consumer's unexpected-error path.
declare function isDocxEditorError(value: unknown): value is DocxEditorError;Classes (30)
Body_2class
A story: the main body of a document, a header or footer variant, or a note's body — and everything in it in reading order.
Its paragraphs are the DOCUMENT'S, not just the top level's. A paragraph inside a table cell, or inside a table inside a cell, or inside a block-level content control, is an ordinary editable paragraph and appears here, exactly as it does in Word's own paragraph collection. A collection listing only direct children would describe a smaller document than the one on screen.
[Body.clear](Body.clear) leaves one empty paragraph, matching what Word produces when a reader selects everything and deletes. A body that already holds no paragraph reports InvalidArgument rather than inventing a block.
declare class Body extends ModelObject| Member | Type | Summary |
|---|---|---|
| bookmarks | BookmarkCollection | Every bookmark declared in this story, in document order. |
| clear | | Empty the story, leaving one empty paragraph behind. |
| contentControls | ContentControlCollection | The content controls this story holds, in document order — the OUTERMOST ones. |
| font | Font | The character formatting of the whole story: what all of it agrees on, and what a write sets. |
| getComments | | The comments anchored in this story, in document order. Replies hang off the comment. |
| insertParagraph | | Add a paragraph at the start or the end of the story. Answers the new paragraph. |
| insertText | | Write text over the whole story, or at either edge of it. Answers the text's own range. |
| lists | ListCollection | Every list this story holds, in the order their numbers first appear. |
| paragraphs | ParagraphCollection | Every paragraph in this story in reading order, at every depth. |
| revisions | RevisionCollection | The tracked changes in this story that this API can publish as typed objects, in document order. |
| search | | Every occurrence of `searchText` in this story, as ranges, in reading order. |
| style | string | The paragraph style, by the name a reader sees in the styles gallery. |
| text | string | The whole story's text. |
BookmarkclassSource ↗
A name a document gives to a stretch of itself.
A bookmark IS its name. OOXML writes it as a pair of markers around the text, and the name is the only thing identifying it — so this object is a name plus the range those markers currently enclose. A bookmark whose markers left with the text they surrounded refuses rather than answering where they used to be.
start, end and delete are absent by design: the first two are document-wide character offsets, the coordinate space this API does not maintain, and delete would have to remove a marker pair, which the canonical write path does not offer.
declare class Bookmark extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| name | string | The name the document declares this bookmark with. |
| range | Range | The text the bookmark's markers enclose. |
| select | | Put the reader's selection on the bookmark and navigate the editor viewport to it. |
BookmarkCollectionclassSource ↗
The bookmarks of a story or a range, as of the batch that loaded them.
Like every collection here, items is the LOADED answer rather than a live view: bookmarks added after the load are not in it, and reaching them means loading again.
declare class BookmarkCollection extends HandleCollection<Bookmark>ClientObjectclassSource ↗
The base every document proxy extends.
A proxy is three things and no more: the context it belongs to, the path that says whether it can be addressed, and the properties a completed load filled in.
A RELEASED proxy still answers what it already knew. Reading a property loaded before the run ended is served from memory, because that value is a copy the consumer already holds — it is not a reach into a document. Anything that would talk to the document (load, a write, a method) refuses with InvalidObjectPath. The line is "does this need the document", not "does this look like a read".
declare abstract class ClientObject implements RuntimeManagedObject| Member | Type | Summary |
|---|---|---|
| (constructor) | | Constructs a new instance of the `ClientObject` class |
| context | RequestContext | The context this object currently belongs to. |
| handle | | The handle to address this object with, or `InvalidObjectPath`. |
| isNullObject | boolean | Whether this object turned out not to exist. |
| load | | Queue the reads that fill in the selected properties. |
| onLoad | | What this kind of object does with a resolved load request. |
| requireAddressable | | The check every call that talks to the document makes first. |
ClientResultclassSource ↗
A value a queued method promised to produce, readable after the next sync().
Deliberately not a Promise. A method call inside a batch has not been sent yet, so there is no pending work to await and nothing that could resolve on its own — awaiting one would deadlock a consumer who then never calls sync(). A result is a box that stays EMPTY until the sync fills it, and reading it early is ValueNotLoaded rather than undefined flowing onwards into something that misinterprets it.
declare class ClientResult<T>The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the ClientResult class.
```ts
const count = body.getParagraphCount();
await context.sync();
console.log(count.value);
```| Member | Type | Summary |
|---|---|---|
| isLoaded | boolean | Whether the sync that fills this has happened. |
| value | T | The value, once a `sync()` has filled it in. |
Comment_2class
A comment: a conversation about a stretch of the document, not a single remark.
[Comment.replies](Comment.replies) holds the answers, and resolving is a property of the whole thread — assigning resolved marks this comment and everything answering it, which is what Word's own pane does.
authorEmail and a writable content are absent: CT_Comment records only an author and initials (Word's addresses live in people.xml, which this API does not read), and a body rewrite is not an operation the canonical write path offers. The comment's text is published as text.
declare class Comment extends CommentBase| Member | Type | Summary |
|---|---|---|
| getRange | | The words the comment is about. |
| replies | CommentReplyCollection | The answers to this comment, in document order. |
| reply | | Answer the comment, over the same words it is anchored to. |
| resolved | boolean | Whether the thread is resolved. |
CommentCollectionclassSource ↗
The comments on a document, story or range, as of the batch that loaded them.
declare class CommentCollection extends HandleCollection<Comment>| Member | Type | Summary |
|---|---|---|
| getFirst | | The first comment. `ItemNotFound` at the sync if there are none. |
CommentReplyclassSource ↗
One answer in a comment thread.
Authored over the parent comment's own range, because that is where the conversation is anchored and OOXML gives a reply no other place to be. Resolving is a property of the whole thread rather than of any one reply — see [Comment.resolved](Comment.resolved).
declare class CommentReply extends CommentBaseCommentReplyCollectionclassSource ↗
The replies to one comment, in thread order, as of the batch that loaded them.
declare class CommentReplyCollection extends HandleCollection<CommentReply>| Member | Type | Summary |
|---|---|---|
| getFirst | | The first reply. `ItemNotFound` at the sync if nobody answered. |
ContentControlclassSource ↗
A part of a document a template marked as a field.
A control is NOT its w:id. The attribute is optional in OOXML and unique nowhere, so a document may hold one control with no id and two with the same one. This object is addressed by an opaque host-minted handle instead, and [ContentControl.id](ContentControl.id) is answered as METADATA — a label the file wrote, empty where it wrote none. getById still exists, because a template author knows their own numbering, and it answers the first match in document order rather than refusing.
A control's contents are not its value. text reads the characters; setValue writes in the vocabulary the control's own type accepts — a declared item for a dropdown, an ISO date for a date picker, a state for a checkbox — because writing "true" into a checkbox's runs would produce a document whose glyph and whose w14:checked disagree.
declare class ContentControl extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| cannotDelete | boolean | Whether the control refuses to be deleted. |
| cannotEdit | boolean | Whether the control's contents refuse to be edited. Resolved like `cannotDelete`. |
| contentControls | ContentControlCollection | The controls INSIDE this one, in document order. |
| delete | | Remove the control. |
| getRange | | The stretch of the story the control's content covers. |
| id | string | The `w:id` the file wrote, as a string, and `''` where it wrote none. |
| insertText | | Put text into the control: over what it holds, or at one end of it. |
| isBound | boolean | Whether the control currently declares an OOXML data binding. |
| paragraphs | ParagraphCollection | The paragraphs the control holds. Empty for an inline control, which holds none. |
| placeholderShown | boolean | Whether the control is showing its prompt rather than a value (`w:showingPlcHdr`). |
| setValue | | Write the control's value. |
| subtype | string | What kind of control it is: `plainText`, `dropDownList`, `checkbox`, `date`, … |
| tag | string | `w:tag` — the machine-readable label a template puts on a field. `''` where absent. |
| temporary | boolean | Whether the control removes its own wrapper on the first content edit (`w:temporary`). |
| text | string | The characters the control encloses, as the document reads them. |
| title | string | `w:alias` — what Word's UI calls the control's title. `''` where absent. |
ContentControlCollectionclassSource ↗
The content controls of a document, story or range, as of the batch that loaded them.
getById answers the first match in document order, because w:id is optional in OOXML and unique nowhere — see [ContentControl](ContentControl) for why choosing predictably beats refusing.
declare class ContentControlCollection extends HandleCollection<ContentControl>| Member | Type | Summary |
|---|---|---|
| getById | | The first control carrying one `w:id`, or `ItemNotFound` where the scope holds none. |
| getByTag | | Every control in the scope carrying one tag, in document order. |
| getByTitle | | Every control in the scope carrying one title, in document order. |
| getFirst | | The first control. `ItemNotFound` at the sync if the scope holds none. |
| getFirstOrNullObject | | The first control, or an object that says `isNullObject` where there is none. |
Document_2class
The document: the root every other object is reached from.
Deliberately thin. A document here is not a bag of content — it is the thing that HAS stories. It publishes the main story as [Document.body](Document.body), plus that story's paragraphs directly as document.paragraphs, because that is how source-compatible code walks a document.
Reached once per [RequestContext](RequestContext) and memoized: context.document is the same object every time, so a property loaded through one reference reads back through any other.
declare class Document extends ModelObject```ts
await runtime.run(async (context) => {
const paragraphs = context.document.paragraphs;
paragraphs.load('items');
await context.sync();
for (const paragraph of paragraphs.items) paragraph.load('text');
await context.sync();
for (const paragraph of paragraphs.items) console.log(paragraph.text);
});
```
The first sync retrieves the collection's items. Once those items are available, the second sync retrieves each paragraph's text.| Member | Type | Summary |
|---|---|---|
| body | Body | The main story. |
| changeTrackingMode | ChangeTrackingMode | Tracking for this server host. Load 'changeTrackingMode' explicitly before reading. Document.load() keeps an empty default property set across hosts. Assignments take effect at sync. TrackMineOnly tracks this runtime's inline text edits using its configured author. TrackAll and browser-host mode control are not supported. Unsupported tracked mutation kinds refuse; the setting is session-local and is not saved as a document-wide policy. |
| comments | CommentCollection | The comments anchored in the main story, in document order. |
| contentControls | ContentControlCollection | The content controls of the main story, in document order — the outermost ones. |
| endnotes | NoteItemCollection | The document's endnotes, in the order its notes part writes them. |
| footnotes | NoteItemCollection | The document's footnotes, in the order its notes part writes them. |
| paragraphs | ParagraphCollection | The main story's paragraphs, in reading order. |
| revisions | RevisionCollection | The tracked changes of the main-body story that this API can publish as typed objects. |
| sections | SectionCollection | The document's sections, in document order. |
DocxEditorErrorclassSource ↗
Every refusal this runtime throws.
Branch on [DocxEditorError.code](DocxEditorError.code), never on the message. Codes are stable public API — added rather than repurposed — so a consumer that handles PropertyNotLoaded by loading and syncing again keeps working across versions.
Nothing from the engine appears in the message. Host rejection reasons, opaque handle refs and offset ranges are all withheld: a ref in a message is a name a consumer can start depending on, and a store's rejection reason would become a documented one the moment somebody matched on it. What a consumer gets instead is a stable code, a fixed sentence, and target — the consumer-facing path they wrote themselves.
declare class DocxEditorError extends Error```ts
try {
await context.sync();
} catch (error) {
if (isDocxEditorError(error) && error.code === 'StaleDocument') {
// Re-read, re-anchor, and reconsider: someone else changed the document first.
}
}
```| Member | Type | Summary |
|---|---|---|
| (constructor) | | Constructs a new instance of the `DocxEditorError` class |
| actualRevision? | number | For `StaleDocument`: the revision the document was actually at. |
| code | DocxEditorErrorCode | Which refusal this is. Stable across versions; the thing to branch on. |
| expectedRevision? | number | For `StaleDocument`: the revision the context had read at. |
| limit? | DocxEditorErrorInit['limit'] | For `ResourceLimitExceeded`: the resource limit that prevented opening. |
| target? | string | Consumer-facing path of the object or property involved, when there is one to name. |
FontclassSource ↗
The character formatting of whatever it belongs to: a story, a stretch of one, or a paragraph.
A font has no identity of its own — it is a view onto its owner's characters and shares its owner's path, so a font reached from a deleted paragraph's range refuses at the same moment the range does rather than holding a stale address.
Reading is AGREEMENT, and null means "no agreed value": every run the owner covers says bold, or the answer is null. Null is also the answer when nothing in range authors the property at all. Both are one answer on purpose, because this API reads what the document AUTHORS rather than what the style cascade computes — a heading whose bold comes from styles.xml reads null. Answering the cascade would let a caller read an inherited value, write it straight back, and silently freeze it into the paragraph as if the author had chosen it.
Assignments within one sync() are ONE write: font.bold = true; font.size = 12 accumulates into a single run-property operation. That is required, not an optimisation — a run-property write carries the run's whole property bag, so a second write planned from the same pre-batch tree would carry a bag the first had already superseded, which the host refuses with ConflictingChanges.
declare class Font extends ModelObject| Member | Type | Summary |
|---|---|---|
| bold | boolean | null | Whether every character agrees it is bold, or `null` where they do not. |
| color | string | null | `#RRGGBB`. `null` where the characters disagree, or where the colour is `auto`. |
| italic | boolean | null | Whether every run in range is italic. `null` where they disagree or none says. |
| name | string | null | The typeface name the characters state, or `null` where they do not agree on one. |
| onLoad | | One read for every property asked for. |
| size | number | null | Points. |
ListclassSource ↗
A list: the set of paragraphs sharing one numbering id.
A list is not an ELEMENT. OOXML has no list — it has paragraphs that each name a w:numId, and a list is the set that name the same one. So [List.id](List.id) is that number, [List.paragraphs](List.paragraphs) is the set, and a list exists exactly as long as some paragraph is still in it.
declare class List extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| getLevelParagraphs | | The list's paragraphs at one level, in reading order. |
| id | number | The `w:numId` the list's paragraphs share — the document's own identity for the list. |
| insertParagraph | | Add a numbered paragraph to the list, at its start or its end. |
| paragraphs | ParagraphCollection | Every paragraph in the list, in reading order. |
ListCollectionclassSource ↗
The lists in a story, as of the batch that loaded them.
declare class ListCollection extends HandleCollection<List>| Member | Type | Summary |
|---|---|---|
| getById | | The list with one `w:numId`, or `ItemNotFound` where the story has none. |
| getFirst | | The first list. `ItemNotFound` at the sync if the story has none. |
ListItemclassSource ↗
A paragraph's membership of a list: which list, and at what level.
listString (the "3." or "iv)" a reader sees) and siblingIndex are absent because they are PAINTED, not authored — computed during layout by a counter that walks the story applying numbering.xml, its abstract-numbering indirection, restarts and overrides. Answering them here would mean a second counter that disagrees with the one on screen the first time a document overrides a level.
declare class ListItem extends ModelObject| Member | Type | Summary |
|---|---|---|
| level | number | How deeply the item is nested: zero for a top-level item, up to eight. |
NoteItemclassSource ↗
One footnote or endnote: text that belongs to the document but not to its flow.
A note IS a story. Its [NoteItem.body](NoteItem.body) is an ordinary [Body](Body) — paragraphs, formatting, styles, the same operations — laid out at the foot of a page or the end of the document rather than in the column, so everything the object model can do to the main story it can do to a note without a second vocabulary.
delete() removes the reference too. A note's body and the citation that reached it are one thing to a reader, and deleting the body alone would leave a mark pointing at nothing. The engine spells that as a package-level transaction, which is why it travels alone in its batch.
declare class NoteItem extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| body | Body | The note's own story. |
| delete | | Remove the note and every reference to it. |
| getNext | | The next note of the same kind. `ItemNotFound` at the sync when this is the last one. |
| text | string | The note's plain text. |
| type | NoteItemType | Whether this is a footnote or an endnote. |
NoteItemCollectionclassSource ↗
The notes of one kind, in the order the notes part writes them.
DocxEditor's own collection type: the pinned reference fixture does not carry Word.NoteItemCollection, so it is not measured for conformance — recorded as an omission in compat/manifest.json — while NoteItem itself is. Without it a note would be unreachable, which is the one thing worse than an unmeasured collection.
declare class NoteItemCollection extends HandleCollection<NoteItem>| Member | Type | Summary |
|---|---|---|
| getFirst | | The first note. `ItemNotFound` at the sync if the document has none of this kind. |
PageSetupclassSource ↗
The page a section is laid out on: paper size, margins, and orientation.
This is w:sectPr — everything a caller usually wants from a section lives here rather than on [Section](Section) itself, which is mostly navigation.
declare class PageSetup extends ModelObject| Member | Type | Summary |
|---|---|---|
| bottomMargin | number | Points. |
| leftMargin | number | Points. |
| orientation | PageOrientation | Which way round the page is. |
| pageHeight | number | Points. |
| pageWidth | number | Points. |
| rightMargin | number | Points. |
| topMargin | number | Points. |
ParagraphclassSource ↗
One paragraph: what it says, what it is, and the ways it can be changed.
Identity is the document's own. [Paragraph.uniqueLocalId](Paragraph.uniqueLocalId) is the w14:paraId the file carries — the value Word writes, and the one commentsExtended.xml and coauthoring merges already anchor to — never a position in a collection. Deleting the paragraph above this one does not change it, which is the point: an agent that read a document, thought about it, and now wants to write to "the paragraph I was looking at" cannot express that with an index. A paragraph the file gave no id gets one deterministically at open, so the same bytes always answer the same identities and saving writes them back.
A structural edit owns its paragraph for the batch: delete(), split() and insertParagraph() change what offsets mean, so a second call in the same sync() that also touches this paragraph is refused with ConflictingChanges rather than planned against coordinates that have stopped describing it. Two syncs get both edits, each exactly as asked.
declare class Paragraph extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| alignment | ParagraphAlignment | How the paragraph's lines are aligned, or `Unknown` where it authors no alignment. |
| clear | | Empty this paragraph's text, leaving the paragraph itself where it is. |
| delete | | Remove this paragraph and everything in it. |
| firstLineIndent | number | Points. Negative for a hanging indent — the first line starting left of the rest. |
| font | Font | The character formatting of this paragraph's characters, and of its paragraph mark. |
| insertParagraph | | Add a paragraph beside this one. Answers the new paragraph. |
| insertText | | Write text over this paragraph or at either edge of it. Answers the written text's range. |
| leftIndent | number | Points. |
| lineSpacing | number | Points between the paragraph's lines. |
| list | List | The list this paragraph is in. |
| listItem | ListItem | Where this paragraph sits in its list. Reading `level` on a paragraph in none refuses. |
| rightIndent | number | Points. |
| spaceAfter | number | Points below the paragraph. |
| spaceBefore | number | Points above the paragraph. |
| split | | Break this paragraph at every occurrence of any delimiter. |
| style | string | The paragraph style, by the name a reader sees in the styles gallery. |
| text | string | This paragraph's text. Readable after `load('text')` and a `sync()`. |
| uniqueLocalId | string | The document's own identity for this paragraph. |
ParagraphCollectionclassSource ↗
The paragraphs of a story, a range, or a list, as of the batch that loaded them.
Contains paragraphs at every depth — inside table cells, nested tables, and block-level content controls — matching Word's own collection rather than only the owner's direct children.
One of the two collections whose members are not plain handles: the pieces a [Paragraph.split](Paragraph.split) answers are filled in by the split's own command rather than by a separate listing read.
declare class ParagraphCollection extends ItemCollection<Paragraph>| Member | Type | Summary |
|---|---|---|
| getFirst | | The first paragraph. `ItemNotFound` at the sync if the collection holds none. |
| getFirstOrNullObject | | The first paragraph, or an object that will report `isNullObject`. |
| getLast | | The last paragraph. `ItemNotFound` at the sync if the collection holds none. |
| getLastOrNullObject | | The last paragraph, or an object that will report `isNullObject`. |
Range_2class
A stretch of a story: two endpoints, each a paragraph and a UTF-16 offset.
A range is a SNAPSHOT, not a tracked region. Its endpoints name the paragraphs they were found in and the offsets they were found at, so it stays meaningful across edits ELSEWHERE in the document and becomes an explicit InvalidObjectPath refusal once one of its paragraphs is gone. What it deliberately does not do is follow edits INSIDE itself: a range over "alpha" whose paragraph then gains a word at offset 0 still names offsets 0..5. Word's own ranges do move, by keeping a live region in the document; this API has none, and pretending otherwise would answer text from a place the caller was not looking at.
That is also why start and end are absent rather than unimplemented — they are document-wide character positions, a different addressing scheme from this API's paragraph identity plus UTF-16 offset. Ask a range for its [Range.paragraphs](Range.paragraphs) instead.
declare class Range extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| bookmarks | BookmarkCollection | The bookmarks whose text this range overlaps, in document order. |
| clear | | Clear this range's content, preserving the surrounding structure. |
| delete | | Delete this range's content. TrackMineOnly preserves inline text as a pending deletion. |
| font | Font | The character formatting of the characters this range covers. |
| hyperlink | string | The hyperlink over these characters: an absolute URL, or `#anchor` for a place in the document. |
| insertComment | | Create a top-level comment anchored to exactly this range. |
| insertParagraph | | Add a paragraph before or after the one this range starts or ends in. |
| insertText | | Write text at or over this range. Answers the range the written text occupies. Await `context.sync()` before loading or addressing that returned range. |
| paragraphs | ParagraphCollection | The paragraphs this range covers, in reading order. |
| search | | Every occurrence of `searchText` inside this range, as ranges. |
| select | | Put the reader's selection on this range and navigate the editor viewport to it. |
| style | string | The paragraph style, by the name a reader sees in the styles gallery. |
| text | string | The text between this range's endpoints. |
RangeCollectionclassSource ↗
Ranges a read produced — the hits of a search, or the pieces a split answered.
Its members are SPANS rather than handles, which is what separates it from the handle-backed collections: each item carries its own paragraph-plus-offset endpoints instead of an opaque host-minted id.
declare class RangeCollection extends ItemCollection<Range>| Member | Type | Summary |
|---|---|---|
| getFirst | | The first range. `ItemNotFound` at the sync if nothing matched. |
| getFirstOrNullObject | | The first range, or an object that will report `isNullObject`. |
| getLast | | The last range. `ItemNotFound` at the sync if nothing matched. |
RequestContextclassSource ↗
What a run hands its callback: one queue, one document, one sync at a time.
sync() is the only thing in this runtime that talks to the document, and it does so exactly once per call — plan the queued actions in order, send ONE batch, hydrate the answers. That is where atomicity comes from: the host commits a batch as one transaction, and the runtime never splits a consumer's sync() into several batches behind their back.
Conditional writes come from the same place. A context that has READ from the document remembers the revision it read at, and a later batch that writes goes out conditional on it, failing StaleDocument if the document moved. That is what stops a decision made from a cached read being applied to a document that has since changed — the hazard the read-decide-write shape of any batching API invites. A context that has read nothing has nothing to be stale about, so its writes go out unconditionally.
declare class RequestContext| Member | Type | Summary |
|---|---|---|
| capabilities | DocumentCapabilities | What the document host behind this context can do. |
| document | Document | The document this run is against. |
| sync | | Send everything queued as one batch and hydrate the answers. |
| trackedObjects | TrackedObjects | Objects kept addressable past the run that created them. See [TrackedObjects](TrackedObjects). |
RevisionclassSource ↗
One tracked change, published when this API can name its Word subtype.
Structural cards whose exact Word subtype cannot be typed — a row, a cell, a section, the table grid — are omitted from the collection rather than shipped as objects with an unpublishable type. That listing is not the collection decision set: see [RevisionCollection](RevisionCollection).
declare class Revision extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| accept | | Keep the change, resolving every site that carries its identity in one transaction. |
| author | string | Who proposed the change. |
| date | Date | null | When they proposed it, or `null` where the file recorded no valid date. |
| range | Range | The words the change covers. |
| reject | | Undo the change, likewise in one transaction. |
| type | RevisionType | What kind of change it is, by Word's own name for it. |
RevisionCollectionclassSource ↗
The tracked changes on a document, story or range, as of the batch that loaded them.
items omits structural cards whose Word subtype this API cannot name; see [Revision](Revision). Collection-wide acceptAll / rejectAll still resolve every store-resolvable revision in this story and refuse atomically if any readOnly or otherwise unsupported revision remains.
declare class RevisionCollection extends HandleCollection<Revision>| Member | Type | Summary |
|---|---|---|
| acceptAll | | Keep every change in this story, as ONE decision and one undo unit. |
| rejectAll | | Undo every change, likewise as one decision. |
SectionclassSource ↗
One section: the document's layout, not its content.
Everything a caller usually wants — paper size, margins, orientation — is on [Section.pageSetup](Section.pageSetup). The section itself is mostly navigation: the story it governs, the header and footer stories it declares, and the section after it.
getHeader and getFooter answer a body that may not exist yet, and say so. A section with no first-page header inherits the previous section's; one at the start of a document with none at all is refused with ItemNotFound rather than minting the part. Word creates the header when a script asks for it — doing that here would make a READ write to the document, and a header that exists only because it was asked about is a header the author never added.
declare class Section extends ModelObject implements PromisedItem| Member | Type | Summary |
|---|---|---|
| body | Body | The story this section governs. |
| getFooter | | The footer story of one variant, as a body. `ItemNotFound` where the document has none. |
| getHeader | | The header story of one variant, as a body. `ItemNotFound` where the document has none. |
| getNext | | The next section. `ItemNotFound` at the sync when this is the last one. |
| pageSetup | PageSetup | The page this section is laid out on. |
SectionCollectionclassSource ↗
The sections of a document, in document order, as of the batch that loaded them.
declare class SectionCollection extends HandleCollection<Section>| Member | Type | Summary |
|---|---|---|
| getFirst | | The first section. `ItemNotFound` at the sync if the document has none. |
TrackedObjectsclassSource ↗
The objects a context keeps addressable beyond the run that created them.
An ordinary proxy stops being usable when its run ends. Tracking one keeps its address alive so a later run(object, callback) can adopt it, and untracking releases it — which matters for long-lived callers, since a tracked object is a document reference that will not be collected on its own.
declare class TrackedObjectsThe constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the TrackedObjects class.
| Member | Type | Summary |
|---|---|---|
| add | | Keep these objects usable after this run ends. |
| remove | | Stop keeping them: they are released when this run ends, like any other object. |
Interfaces (12)
CreateServerOptionsinterfaceSource ↗
How DocxEditor.createServer opens a document.
Opening DOCX bytes is a bounded parse: decompression-ratio and size caps, part and relationship path validation, DTD- and entity-free XML. Malformed input returns InvalidArgument. Resource refusals return ResourceLimitExceeded, with limit identifying the exceeded cap. File-controlled details and internal parser messages are never included.
The bounded parse is complete when this promise resolves. The runtime does not retain the caller's Uint8Array, so the caller may reuse or transfer that input buffer afterward.
interface CreateServerOptions| Member | Type | Summary |
|---|---|---|
| author? | string | Who comments and tracked text edits written by this runtime are recorded as. |
| limits? | DocumentLimits | Budgets for the bounded reader — archive size, part count, and XML elements. |
| modules? | readonly EditorModule[] | Capability modules to register. Collaboration attaches only through a collaboration contribution on this list. |
| revisionTextView? | RevisionTextView | Revision view for ordinary Office-compatible `text` loads and `search()` calls. |
DocumentCapabilitiesinterfaceSource ↗
Capabilities exposed by a DocxEditor runtime, frozen for its lifetime.
interface DocumentCapabilities| Member | Type | Summary |
|---|---|---|
| document | boolean | There is a document to address at all. False for a browser host between mounts. |
| events | boolean | The host raises document events. |
| layout | boolean | The host lays the document out, so paginated positions are meaningful. |
| save | boolean | `save()` is offered — true for a server runtime, false for one borrowing an editor. |
| scrolling | boolean | The host can be scrolled to a position. |
| selection | boolean | The host has a user selection to read or move. |
DocumentLimitsinterfaceSource ↗
Resource budgets applied while opening DOCX bytes, subject to engine ceilings.
interface DocumentLimits| Member | Type | Summary |
|---|---|---|
| maxRelationships? | number | Most relationships the package may declare. |
| maxXmlParts? | number | Most XML parts the package may hold. |
| xml? | DocumentXmlLimits | Per-part XML caps. |
| zip? | DocumentZipLimits | Archive-level caps. |
DocumentXmlLimitsinterfaceSource ↗
Resource limits for each parsed XML part.
interface DocumentXmlLimits| Member | Type | Summary |
|---|---|---|
| maxBytes | number | Most bytes any one XML part may be. |
| maxElements? | number | Most elements any one XML part may contain. Defaults to the engine budget (10,000,000); callers may raise it up to the engine ceiling (50,000,000). |
DocumentZipLimitsinterfaceSource ↗
Resource limits for the DOCX archive.
interface DocumentZipLimits| Member | Type | Summary |
|---|---|---|
| maxEntries | number | Most entries the archive may contain. |
| maxRatio? | number | Highest tolerated decompression ratio — the zip-bomb guard. |
| maxTotalBytes | number | Most bytes the archive may decompress to in total. |
DocxEditorErrorInitinterfaceSource ↗
The fields a [DocxEditorError](DocxEditorError) is constructed from.
interface DocxEditorErrorInit| Member | Type | Summary |
|---|---|---|
| actualRevision? | number | The revision the document was actually at, for `StaleDocument`. |
| code | DocxEditorErrorCode | Which refusal this is. The stable thing to branch on. |
| expectedRevision? | number | The revision the context had read at, for `StaleDocument`. |
| limit? | 'zip.maxEntries' | 'zip.maxTotalBytes' | 'zip.maxRatio' | 'xml.maxBytes' | 'xml.maxElements' | 'xml.maxDepth' | 'maxXmlParts' | 'maxRelationships' | The resource limit exceeded while opening a document. |
| target? | string | The consumer-facing path of the object or property involved — `document.body.text`, not a handle. Omitted when there is nothing to name. |
DocxEditorNamespaceinterfaceSource ↗
The entry point, as much of it as works without an editor.
An object rather than a TypeScript namespace: a namespace with runtime members is a declaration-merging construct that does not survive being re-exported through a bundler as predictably, and DocxEditor.createServer reads the same either way.
Import from @docx-editor.dev/editor-api/browser for the same namespace plus createBrowser.
interface DocxEditorNamespace| Member | Type | Summary |
|---|---|---|
| createCollaborative | | A DOM-free runtime over one experimental collaboration replica. |
| createServer | | A runtime over DOCX bytes. Additionally offers `save()`. |
DocxEditorRuntimeinterfaceSource ↗
A runtime: one document host, many runs.
Runs are ISOLATED, not serialized. Every [DocxEditorRuntime.run](DocxEditorRuntime.run) gets its own context and its own queue, so two runs cannot interleave into one batch, and a run started inside another run works instead of waiting for a lock its own caller holds. Batches are still ordered — each sync() sends one atomic batch, in the order the sync() calls happen.
Disposal is final: [DocxEditorRuntime.dispose](DocxEditorRuntime.dispose) releases the host once and is safe to call again, and every later run fails with RuntimeDisposed.
interface DocxEditorRuntime| Member | Type | Summary |
|---|---|---|
| capabilities | DocumentCapabilities | What the document host behind this runtime can do. Frozen at construction. |
| dispose | | Release the host. Idempotent. |
| run | | Run one batch of work against the document. Answers with the callback's value. |
| run | | Run one batch of work, adopting objects a previous run tracked. |
DocxEditorServerRuntimeinterfaceSource ↗
A runtime over DOCX bytes rather than a live editor — what DocxEditor.createServer answers.
Adds [DocxEditorServerRuntime.save](DocxEditorServerRuntime.save) to the shared contract, because a server runtime owns its document and can serialize it; a browser runtime borrows the editor's and cannot.
interface DocxEditorServerRuntime extends DocxEditorRuntime| Member | Type | Summary |
|---|---|---|
| save | | The current document as a fresh, caller-owned DOCX byte array. |
EditorModuleinterfaceSource ↗
Capability module accepted by [createServer](createServer). Collaboration attaches through a collaboration contribution. Other contributions are ignored here.
interface EditorModule| Member | Type | Summary |
|---|---|---|
| collaboration? | CollaborationModuleContribution | |
| id | string |
LoadQueryOptionsinterfaceSource ↗
The object form of load(...): which properties, and how much of a collection.
An unknown key, a non-integer top, a property name that is not an identifier, or a value of the wrong type is refused as InvalidArgument here, naming the option — a misspelled key is the difference between "load selected properties" and "load nothing", which would otherwise surface as a PropertyNotLoaded much later at a call that looks correct.
interface LoadQueryOptions| Member | Type | Summary |
|---|---|---|
| expand? | string | readonly string[] | Reserved for Office.js source compatibility. Navigation-property expansion is not supported yet: a non-empty value is refused as `InvalidArgument`. Omit it or pass an empty array. |
| select? | string | readonly string[] | Which properties to load. |
| skip? | number | For a collection: skip this many items first. |
| top? | number | For a collection: at most this many items. |
SearchOptionsinterfaceSource ↗
How a search is narrowed.
Every flag is honoured or REFUSED — never quietly ignored. A search that accepted matchWildcards and then ran a plain-text scan would answer the wrong offsets to a caller who edits at them, so the unimplemented options reach the host and come back as NotSupported.
They are declared here rather than left off the type because omitting them would make { matchWildcards: true } a compile error in code that is otherwise source-compatible with Word. The honest answer to that code is a runtime refusal naming the option, not a type error naming the interface.
interface SearchOptions| Member | Type | Summary |
|---|---|---|
| ignorePunct? | boolean | Not implemented; `true` is refused with `NotSupported`. |
| ignoreSpace? | boolean | Not implemented; `true` is refused with `NotSupported`. |
| matchCase? | boolean | Match the query's case. Off by default, like Word's Find. |
| matchWholeWord? | boolean | Only match where the query stands alone as a word. |
| matchWildcards? | boolean | Not implemented; `true` is refused with `NotSupported`. |
Type aliases (21)
BesideLocationtypeSource ↗
Which side of a paragraph or a range a new paragraph goes on.
type BesideLocation = Extract<InsertLocation, 'Before' | 'After'>;BodyInsertParagraphLocationtypeSource ↗
Where a story accepts a paragraph. Start/End mean "before the first"/"after the last".
type BodyInsertParagraphLocation = Extract<InsertLocation, 'Start' | 'End'>;BodyInsertTextLocationtypeSource ↗
Where a story accepts text: over all of it, or at either edge.
type BodyInsertTextLocation = Extract<InsertLocation, 'Replace' | 'Start' | 'End'>;ChangeTrackingModetypeSource ↗
Office.js tracking mode names. TrackAll is recognized but currently refused.
type ChangeTrackingMode = 'Off' | 'TrackAll' | 'TrackMineOnly';ContentControlLockStatetypeSource ↗
The lock a control carries. ST_Lock, spelled as the schema spells it.
type ContentControlLockState = 'unlocked' | 'sdtLocked' | 'contentLocked' | 'sdtContentLocked';ContentControlSubtypetypeSource ↗
The control types this API can create. Picture and repeating section are deferred.
type ContentControlSubtype = 'richText' | 'plainText' | 'dropDownList' | 'comboBox' | 'date';ContentControlValuetypeSource ↗
What a control's own type accepts as a value.
A discriminated union rather than unknown: a dropdown and a checkbox do not take the same kind of thing, and a single setValue(value: string) would have to guess what 'true' means to a date picker.
type ContentControlValue = {
readonly kind: 'text';
readonly text: string;
} | {
readonly kind: 'listItem';
readonly value: string;
} | {
readonly kind: 'checkbox';
readonly checked: boolean;
}
/** `YYYY-MM-DD`, or a full ISO-8601 instant. */
| {
readonly kind: 'date';
readonly iso: string;
};CreateCollaborativeOptionstypeSource ↗
Options for [createCollaborative](createCollaborative).
type CreateCollaborativeOptions = CreateServerOptions;DocxEditorErrorCodetypeSource ↗
What went wrong, as a value a consumer may branch on.
type DocxEditorErrorCode =
/** A property was read before a `load(...)` for it completed in a `sync()`. */
'PropertyNotLoaded'
/** A `ClientResult` value was read before the sync that fills it. */
| 'ValueNotLoaded'
/**
* The object cannot be addressed, in either of the two ways that happens.
*
* NOT YET: an item accessor answers a proxy the read that names it has not answered for, and it
* becomes usable at the next `sync()`. NOT ANY MORE: its run ended and nothing tracked it, which
* is terminal. One code because from a consumer's side both are "this object cannot be used
* here"; the message says which one, because the fix for one is not the fix for the other.
*/
| 'InvalidObjectPath'
/** The object still belongs to a run that has not finished, so it cannot be handed over. */
| 'ObjectInUse'
/** An argument or load option this API does not accept. */
| 'InvalidArgument'
/** Opening the document exceeded a bounded reader resource limit. */
| 'ResourceLimitExceeded'
/** The collection has no such item — `getFirst()` on an empty one. */
| 'ItemNotFound'
/** The host cannot do this at all — a capability it reports false. */
| 'NotSupported'
/**
* The member exists in this API's shape but this version does not implement it.
*
* Distinct from `NotSupported`, which is about the HOST: a headless document really has no
* caret, and no version of this library will give it one. This code means the library, not the
* document, is the limit — so a consumer knows to check the release notes rather than the host.
*/
| 'NotImplemented'
/**
* Two calls in one batch make claims on the same paragraph that cannot both hold.
*
* A batch is one transaction planned against the state at its start, which stops being
* unambiguous once two calls restructure the same paragraph. Split them across two `sync()`
* calls and each gets exactly what it asked for.
*/
| 'ConflictingChanges'
/** The request context's `run` has finished, so it can no longer be used. */
| 'InvalidRequestContext'
/** The runtime was disposed. Every later operation fails this way. */
| 'RuntimeDisposed'
/** The document moved under a context that had already read from it; nothing was applied. */
| 'StaleDocument'
/** The host is live but holds no document right now — an editor between mounts. */
| 'DocumentUnavailable'
/** The document refused the change, or answered something this runtime cannot use. */
| 'GeneralException';HeaderFooterTypetypeSource ↗
Which header or footer of a section: Word's own three variants.
type HeaderFooterType = 'Primary' | 'FirstPage' | 'EvenPages';InsertLocationtypeSource ↗
Every place this API can insert at. Individual members accept a subset.
type InsertLocation = 'Replace' | 'Start' | 'End' | 'Before' | 'After';LoadOptiontypeSource ↗
Everything load(...) accepts: one property name, several, or a [LoadQueryOptions](LoadQueryOptions) object.
type LoadOption = string | readonly string[] | LoadQueryOptions;```ts
paragraph.load('text');
paragraph.load(['text', 'style']);
paragraphs.load({ select: 'items', top: 5 });
```
Collections load their `items`; properties such as `text` are loaded on each item after the collection has been synced.NoteItemTypetypeSource ↗
Which kind of note: Word's own two.
type NoteItemType = 'Footnote' | 'Endnote';PageOrientationtypeSource ↗
Which way round a page is, in Word's own spelling.
Capitalised here and lower-case in the engine on purpose: the engine speaks OOXML's vocabulary, and this is the public API's. The mapping lives in this file and nowhere else.
type PageOrientation = 'Portrait' | 'Landscape';ParagraphAlignmenttypeSource ↗
Paragraph alignment values readable and writable through this object model.
type ParagraphAlignment = 'Mixed' | 'Unknown' | 'Left' | 'Centered' | 'Right' | 'Justified';ParagraphInsertTextLocationtypeSource ↗
Where a paragraph accepts text: over all of it, or at either edge of it.
type ParagraphInsertTextLocation = Extract<InsertLocation, 'Replace' | 'Start' | 'End'>;RangeInsertTextLocationtypeSource ↗
Where a range accepts text. See Range#insertText for what Before/Start mean here.
type RangeInsertTextLocation = InsertLocation;RevisionTextViewtypeSource ↗
The tracked-revision view used by this runtime's ordinary Office-compatible text reads.
allMarkup preserves the historical behavior. original matches Word's Original review view: pending deletions remain visible and pending insertions stay hidden.
This is a DocxEditor runtime option. It is not part of the Office.js object model.
type RevisionTextView = 'allMarkup' | 'original';RevisionTypetypeSource ↗
Word's own names for a kind of change.
The WHOLE upstream vocabulary, because a declaration says what a caller may be handed and a caller switching on it should not have to be told which subset this engine happens to produce. Seven of these actually occur as published objects — insert, delete, replace, the two property kinds and the two move halves. Structural cards whose exact Word subtype this API cannot name are omitted from items; collection-wide decisions still resolve every store-resolvable revision. See compat/manifest.json.
type RevisionType = 'None' | 'Insert' | 'Delete' | 'Property' | 'ParagraphNumber' | 'DisplayField' | 'Reconcile' | 'Conflict' | 'Style' | 'Replace' | 'ParagraphProperty' | 'TableProperty' | 'SectionProperty' | 'StyleDefinition' | 'MovedFrom' | 'MovedTo' | 'CellInsertion' | 'CellDeletion' | 'CellMerge' | 'CellSplit' | 'ConflictInsert' | 'ConflictDelete';RunCallbacktypeSource ↗
What a run callback is given, and what it may answer with.
type RunCallback<T> = (context: RequestContext) => Promise<T>;SelectionMode_2type
Where a selection lands: over the range, or collapsed to one of its edges.
type SelectionMode = 'Select' | 'Start' | 'End';Variables (1)
DocxEditorconstSource ↗
The entry point: open a document and get a runtime to work against.
Import from @docx-editor.dev/editor-api/browser for the same namespace plus createBrowser, which borrows a live editor instead of owning bytes.
DocxEditor: DocxEditorNamespace```ts
import { DocxEditor } from '@docx-editor.dev/editor-api';
const runtime = await DocxEditor.createServer(bytes, { author: 'Payroll bot' });
await runtime.run(async (context) => {
const body = context.document.body;
body.load('text');
await context.sync();
});
const saved = await runtime.save();
```