Word fidelity
Word feature support for editing, rendering, and structural round-trip fidelity, plus security and API stability.
Product behavior
| Area | Behavior |
|---|---|
| Browser editor | Parses, renders, edits, and serializes DOCX data in the browser. |
| Server editing API | Runs where you host it. |
| File format | Reads and writes Office Open XML (OOXML). |
| Unsupported content | Preserves unmodeled markup and package payloads when you edit other content. |
| Support | Contact docx-editor@eigenpal.com. |
Feature matrix
The matrix reports three separate support axes.
| Axis | Question |
|---|---|
| Editing | Can a user or API change the feature? |
| Rendering | Does the feature display like Microsoft Word? |
| Round-trip | Does it survive open, edit, save, and reopen? |
| Status | Meaning |
|---|---|
| Full | Matches Word behavior for this feature. |
| Partial | Works with the limits in its note. |
| Render only | Displays correctly but is not editable. |
| Preserved | Remains as inert content through editing and save. |
| No | Is not supported. |
Text and formatting
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Bold, italic, underline, strikethrough | Full | Full | Full | |
| Format painter | Partial | Full | Full | Copies character formatting, and paragraph formatting when the selection covers the paragraph mark. Paragraph borders and character styles stay on the target. |
| Subscript & superscript | Full | Full | Full | |
| Font family & size | Full | Full | Full | Register custom fonts with the fonts prop. The editor fetches your URLs and checks each hash. Theme fonts come from the OOXML theme. Word-accurate wrap and pagination need real font bytes, so the optional @docx-editor.dev/fonts package supplies substitutes for common Word fonts. Word's five document defaults match advance widths exactly. Century Gothic loads on demand and runs within 1%, so a wrap point can still move. A family with no metric-compatible substitute keeps your own measurement rather than being given an arbitrary face. packagedFonts() serves all six on demand and reaches no third party. It loads a family when a document names it, or when that family is the default face. googleFonts() adds a pinned open-licensed catalog once an app opts into the network. Both are resolvers with the same call shape, so useFonts and useDocxSource compose them as a list in precedence order. A later origin is told which faces an earlier one can already paint, so composing them never downloads the same face twice. |
| Embedded fonts | Partial | Full | Preserved | The editor de-obfuscates the fonts in word/fonts on load and measures text with them. No configuration and no network request are necessary. The binaries round-trip on save. The editor does not add new embedded fonts. |
| Text color (RGB + theme colors) | Full | Full | Full | Theme color references (accent1...) round-trip as references, not flattened to hex. |
| Highlight & shading | Full | Full | Full | Word highlight palette plus arbitrary w:shd fills. |
| Right-to-left & bidirectional text | Full | Full | Full | Bidi layout with mirrored alignment; Hebrew locale ships in @docx-editor.dev/i18n. |
| Text effects (outline, shadow, emboss, emphasis mark) | No | Partial | Full | Opaque solid w14:textOutline with an explicit RGB color renders. Theme-colored, transparent, gradient, dashed, compound, and inset outlines do not render. Legacy outline, shadow, emboss, imprint, and emphasis marks are preserved but do not render. Text effects have no toolbar controls. |
| Hidden text (vanish) | No | Full | Full | The editor does not draw w:vanish runs and gives them no space, so pages break where Word breaks them. The text survives a round trip. There is no "show hidden text" option. A paragraph with a vanished mark still occupies a line. |
| Math equations (OMML) | No | Partial | Full | Equations round-trip verbatim as raw OMML and show a styled text fallback. Laid-out math and equation editing are not built yet. |
| Symbol characters (w:sym) | Partial | Full | Full | Symbol runs render and survive editing and save. The editor requests fonts for symbol runs, SYMBOL fields, and used numbering markers through the configured font resolver. You can insert a symbol from the Insert menu. Existing symbol run properties are not editable. |
Paragraphs and styles
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Alignment & justification | Full | Full | Full | Justified East Asian lines distribute inter-character spacing. The last line stays left-aligned. Tabs and float passages retain their reserved positions. |
| East Asian typography | Preserved | Partial | Full | Protects graphemes, punctuation, and full-width number groups across run boundaries. East Asian font hints cover supported punctuation, symbols, Greek, and Cyrillic ranges while preserving explicit symbol fonts. Reads kinsoku, wordWrap, overflowPunct, strictFirstAndLastChars, language-specific custom line-break sets, and characterSpacingControl. Korean character wrapping follows wordWrap. Compression uses deterministic punctuation and kana advance reductions; font-specific optical compression and vertical Japanese composition are not modeled. Typography settings have no dedicated UI. |
| Line & paragraph spacing | Full | Full | Full | Space before, space after, and line spacing (single, multiple, exactly, at least) all reach pagination. A 1.5-spaced or double-spaced document breaks pages where Word breaks them. The paragraph mark size counts in the last line metrics, like Word. Contextual spacing drops the gap between neighbours of the same style, and the Paragraph dialog sets it. Automatic spacing (w:beforeAutospacing, w:afterAutospacing) uses 14pt in body paragraphs and 0pt in list items and table cells. |
| Keep with next, keep lines, widow/orphan control | Full | Full | Full | w:keepNext, w:keepLines, w:widowControl and w:pageBreakBefore all reach pagination, and the Paragraph dialog sets each of them. A value a style supplies reads through the cascade, so a checkbox shows what is in force rather than only what the paragraph authors itself. |
| Indentation (incl. hanging indents) | Full | Full | Full | Left, right, first-line, and hanging indents all reach line geometry, so an indented first line starts where Word starts it. Increase Indent and Decrease Indent are on the toolbar, on Tab, and on Ctrl+M. Inside a list they change the level, so the marker changes too. |
| Paragraph styles (Heading 1, Quote, custom styles) | Full | Full | Full | The style picker applies document styles, including custom styles with their numbering and indents. Pressing Enter at the end of a paragraph starts the next one in the style that the current style names as its follower (w:next), so a heading is followed by body text. Defining a new style in the UI is not supported yet. |
| Paragraph borders & fills | Partial | Full | Full | Paragraph shading (w:shd) is editable. Borders render the common ST_Border styles: single, double, dashed, and dotted. Thick, 3-D, inset, and outset styles use CSS approximations, and art borders paint as a solid rule. Borders round-trip, but you cannot add, change, or remove them in the editor yet. |
| Tab stops & leaders | Partial | Full | Full | Existing tab stops render, with right and decimal tabs and dot, hyphen, and underscore leaders. Positional tabs (w:ptab) render too, so a contents line reads as one: entry left, leader dots between, page number right. The document's own w:defaultTabStop is honored, in the body and in headers and footers. The Paragraph dialog sets, clears, and replaces tab stops, including clearing one that a style supplies. Bar tabs are preserved on save but aren't drawn or editable. |
| Drop caps & text frames (framePr) | No | Partial | Full | In single-column sections, body text frames with numeric x, y, and width use page, margin, or text anchors without adding their height to paragraph flow. Adjacent paragraphs with identical frame properties share one frame. Following text wraps around frames or clears them for none and notBeside. Continuous sections start below preceding frames. Text remains selectable and editable; frame creation and resizing have no UI. Centered auto-sized and supported fixed-width PAGE footer frames retain their specialized layout. Drop caps, fixed-height frames, alignment-based positions, and frames with unsupported content stay in ordinary flow. Upward text-relative offsets and frame groups that block a full fresh page use ordinary flow. All frame properties survive save. |
| Automatic hyphenation | No | No | Preserved | Document hyphenation settings round-trip; the layout engine does not hyphenate. |
Body text frames with numeric w:x, w:y, and w:w retain their authored positions.
Text wraps inside the frame width and remains selectable and editable.
Adjacent paragraphs with identical w:framePr attributes share one frame.
Frames follow their next ordinary paragraph across page breaks and do not consume normal paragraph height.
Following text wraps around frames; none and notBeside move that text below the frame.
This supports auto-height frames in single-column sections with page, margin, or text anchors. Drop caps, fixed heights, alignment-based positions, and frames containing drawings or notes retain ordinary layout. Upward text-relative offsets also retain ordinary layout. Frame groups that block the full text width and leave no vertical room on a fresh page use ordinary layout. The editor preserves their properties on save. A following continuous section starts below the preceding frames. There is no interface for creating, moving, or resizing text frames.
Lists and numbering
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Bullet lists (multi-level) | Full | Full | Full | The toolbar toggle creates the numbering definition on first use, so a document that never carried a list can start one. It also applies the List Paragraph style, the way Word does, which is what closes the space between consecutive items. Turning the list off leaves the paragraph in List Paragraph, and indented, as Word does; pressing Enter on an empty item leaves the list and returns to the margin. Tab and the indent buttons change the level, and the marker changes with it. |
| Numbered lists (decimal, roman, letters) | Full | Full | Full | Numbered lists take the List Paragraph style on the same terms as bulleted ones, so consecutive items close up. |
| Custom numbering definitions & style-linked numbering | Full | Full | Full | Numbering attached to custom paragraph styles resolves with Word’s precedence rules. |
| List continuation & restart | Full | Full | Full | |
| Picture bullets (numPicBullet) | No | No | Preserved | Not rendered and not editable. The numPicBullet definition and its markup are preserved on save. |
Tables
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Table insertion & cell editing | Full | Full | Full | Explicit Word compatibility modes 11, 12, and 14 preserve content alignment for supported full-width AutoFit tables. The same settings apply in body, header, footer, text-box, and note stories. Other table layouts keep their existing geometry. |
| Row/column insert, delete, resize | Full | Full | Full | Hover controls insert a row or column. Drag a divider or the outer right edge to resize. The context menu adds seven structural actions. Both adapters ship the same table chrome. Tables stay read-only in the automation object model. |
| Cell borders & shading | Partial | Full | Full | Both adapters expose contextual toolbar controls that set borders and fill on the selected cells. Authored table and cell borders and table-style shading render and round-trip. |
| Merged cells (horizontal & vertical) | No | Full | Full | Authored merges render and round-trip. A row inserted at a boundary inside a vertical merge extends the merge by one row and keeps one cell per column. The merge and split commands are declared but refused. Column insert, delete, and resize on a merged table report the engine reason. |
| Tables split across pages | Full | Full | Full | Rows split mid-content with correct cut borders. Vertically merged cells repaint on continuation pages, like Word. Repeated headers and bounded complete text rows reserve their shared horizontal border before pagination. This boundary adjustment excludes spaced cells, vertical merges, split rows, positioned tables, drawings, nested tables, and vertical text. |
| Nested tables | Partial | Full | Full | The innermost table owns the resize controls, the structural edits, and the cell borders and fill. Outer tables stay unchanged through save and reopen. |
| Table styles & conditional formatting (header row, banding) | Partial | Full | Full | Table styles resolve through their basedOn chain, and a table that names no style resolves the document default. Borders, cell margins, shading, and conditional paragraph and run formatting come from styles.xml, so a header row comes out bold and centered. w:tblLook gates which conditional formats apply, and an explicit w:cnfStyle wins. Conditional cell margins and a table-style picker are not built yet. |
| Floating tables (tblpPr anchored position) | No | Partial | Full | An anchored table uses tblpXSpec or tblpX across the text, margin, or page box, and tblpY or tblpYSpec against its vertical anchor. Body text wraps beside supported floating tables and below full-width tables, including authored text distances. Text-anchored tables with numeric vertical offsets move with their following paragraph and do not add table height to paragraph flow. Negative offsets retain their position when clear of preceding text; intersecting tables move below that text. Text-anchored tables taller than a page, marked no-overlap, using vertical alignment, or affected by earlier wrapping objects retain row pagination. Simple terminal empty anchors retain their shared-page layout. Floating-table positioning has no editing UI. |
| Vertical cell text (textDirection) | No | Full | Full | tbRl and btLr cell text renders through writing-mode and round-trips. You cannot set it from the UI. |
Explicit Word compatibility modes 11, 12, and 14 preserve content alignment for supported full-width AutoFit tables. This applies in body, header, footer, text-box, and note stories. The table must have explicit zero indentation, left alignment, zero cell spacing, and consistent outer cell margins. Its complete authored grid must equal the text-column width plus those margins. Other layouts keep their existing geometry, including nested tables and files without an explicit compatibility mode.
Body text wraps beside supported floating tables and below tables that cover the text column. The table's text distances keep the authored gap between its border and surrounding text. Text-anchored tables with numeric vertical offsets follow their next ordinary paragraph onto its page and column. Negative offsets remain in place when they clear preceding text. A table that intersects preceding text moves below that text.
Text-anchored tables taller than a content page retain row pagination. Text-anchored tables marked no-overlap or using vertical alignment also retain their normal flow behavior. Tables whose cells can wrap around earlier floating objects also retain row pagination. Simple tables can share a terminal empty paragraph without shrinking that paragraph or adding a blank page. Floating-table properties survive save, but have no editing interface.
When you compare a multipage table, check the space between each repeated header and its first body row. The table pagination note lists the shared-border measurement limits. Keep the original document when you report a spacing issue.
Images and drawings
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Inline images (paste, drag-drop, resize) | Partial | Full | Full | The engine lays out and paints embedded PNG, JPEG, and GIF at the authored size. JPEG validation accepts large metadata segments and accounts for EXIF-oriented intrinsic dimensions without rewriting the photo. Both adapters ship insert and overlay authoring: the Insert menu, toolbar, properties dialog, and keyboard resize through the shared engine commands. An inserted image keeps its natural size when it fits and scales down proportionally to its cell, column, or page content box when it does not. |
| Floating images & wrap modes (square, topAndBottom...) | Partial | Full | Full | Nine wrap modes, exclusion reflow, z-order, and drag and resize in both adapters. In-front and behind-text overlays are not cropped by their anchor cell. Authored anchor text distances are preserved. Text clears rectangular gaps narrower than the next glyph. Both share setImageWrapType and toolbarCommandState. |
| BMP and WebP images | No | Full | Full | The browser decodes these and the editor paints them at the authored size, like PNG or JPEG. BMP covers what older documents carry, including top-down bitmaps and the 12-byte BITMAPCOREHEADER. WebP covers the lossy, lossless, and extended containers. Inserting a new one is not supported yet. |
| SVG images | No | Full | Full | Embedded SVG paints at the authored size. The browser renders it in secure static mode, so scripts and external references inside the file stay inert. Inserting a new SVG is not supported yet. |
| WMF / EMF legacy vector images | No | Partial | Full | The browser rasterizes the metafile and the editor paints it at the authored extent. A metafile that will not convert keeps its extent and shows a labelled placeholder. The original bytes round-trip untouched. |
| TIFF images | No | Partial | Full | The browser decodes baseline TIFF and the editor paints it at the authored extent. A multi-page file shows its first page. A flavour that will not decode keeps its extent and shows a labelled placeholder. Inserting a new TIFF is not supported yet. |
| Tracked image changes | Partial | Full | Full | Suggesting mode records image insertion and deletion. Review actions can accept or reject both changes. Image property edits are unavailable in suggesting mode. |
| Text boxes | No | Partial | Preserved | Anchored text boxes render their content clipped inside the authored extent. This works in the body, in headers, and in footers, including page-relative anchors. PAGE, NUMPAGES, and SECTIONPAGES fields inside a header or footer text box are evaluated per page. The content is read-only. Inline text boxes, linked chains, autofit, and rotation render as a placeholder or clip. |
| Drawing shapes & geometry | No | Partial | Preserved | Solid rectangles, ellipses, bounded polygon geometry, and grouped shapes render with sRGB or theme colors. Other payloads reserve their extent with a placeholder. |
| Legacy VML pictures, annotation groups & straight WordArt | No | Partial | Preserved | Standalone w:pict supports bounded unrotated photos and groups of photos, simple solid geometry, arrowed lines, and straight fit-to-box WordArt. Previews do not replace canonical VML or add media parts. Unknown templates, unsupported members, rotation, and clipped groups remain opaque as a whole. VML-only MC fallbacks are unchanged. |
| Picture cropping (srcRect) | Partial | Full | Full | Crop renders and round-trips. The properties dialog edits the crop in percent in both adapters. |
| Picture adjustments (brightness, contrast, recolor) | No | Partial | Full | Brightness, contrast, grayscale, and bilevel black-and-white adjustments render in the editor. Image alpha and authored adjustment markup are preserved. PDF export does not apply these adjustments. |
| Picture effects (shadow, glow, reflection) | No | No | Preserved | Not painted and not editable. Authored effect markup and effectExtent spacing are preserved. |
| Charts (DrawingML) | No | Partial | Preserved | The extent is reserved with a labelled placeholder. The chart payload is preserved generically, not edited. |
| SmartArt & diagrams | No | Partial | Preserved | Same placeholder policy as charts. The payload is preserved inertly. |
| Ink annotations (w:ink) | No | No | Preserved | Not rendered and not editable. Ink markup is preserved generically on save. |
Page layout, headers, and footers
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| True pagination (Word-metric pages) | Full | Full | Full | The layout engine paginates like Word: page breaks, keep rules, and paragraphs split across pages. You can insert a hard page break, which writes `w:br w:type="page"`. |
| Sections (margins, size, orientation, per-section headers) | Partial | Full | Full | Page size, orientation, and margins are editable per section or for the whole document, from the Page Setup dialog or a ruler drag. Each section paginates against its own geometry, so a mixed portrait and landscape document renders as Word shows it. You can insert a next-page or a continuous section break; a continuous one keeps the new section on the sheet the previous section ended. Even and odd page break parity and per-section columns are not modelled yet. |
| Headers and footers (edit in place) | Partial | Full | Full | Both adapters have scoped header and footer editing: enter and exit the story, create and remove it, link and unlink to the previous section, and set the title-page and even/odd options. They also insert PAGE, NUMPAGES, and SECTIONPAGES. `editHeaderFooter` takes `variant`, `evenPage`, and `firstPage` on the shared Editor contract. Per-section first, even, and default variants paint like Word. Editing inside a header or footer matches the body: lists, tables, content controls, pictures, fonts, comments, bookmarks, and page setup all act on the story you are in. Tracked changes work in a header or footer: you can suggest an edit there, and the review list shows it with the accept and reject verbs. Selection and comment highlight bands paint in the body only. Watermark authoring is not supported. |
| Watermarks (text & image) | No | Partial | Preserved | The supported unrotated standalone VML subset can paint in header parts. Rotated or curved watermark templates remain opaque, and watermark authoring is unavailable. Authored markup and package relationships are preserved through save. |
| Footnotes and endnotes | Partial | Partial | Full | Both adapters have a typed note model, note layout (pageBottom, beneathText, sectEnd, docEnd), scoped note editing, insert, delete, convert, and chrome slots. A footnote stays whole with its reference: when it cannot fit below the referencing line, the line moves to the next page instead of the note splitting. Only a note taller than the page note column splits across pages. Overflow sheets retain separate page rectangles for painting and hit testing. Editing inside a note matches the body: lists, tables, content controls, pictures, fonts, comments, bookmarks, and page setup. Suggesting mode tracks an inserted reference and requires reference deletion to propose note removal. Notes in headers and footers are out of scope. |
| Multi-column layout | No | Partial | Full | Section w:cols count, gap, separator, and equal or unequal widths paginate into columns. An explicit column break leaves the break paragraph's empty remainder at the top of the next column. Continuous multi-column sections balance. Column editing chrome is not exposed. |
| Page borders | No | Full | Full | Page borders render with z-order, offset modes, and first-page filters. You cannot edit them from the UI. |
| Line numbers (lnNumType) | No | No | Full | Parsed and round-tripped; not drawn in the margin. |
| Different even & odd headers | Partial | Full | Full | The page number in the document selects the first, even, or default variant, so the alternation carries across section breaks. You can edit each variant in an open furniture scope. `editHeaderFooter({ variant: 'even' })` creates or opens the even story and enables `w:evenAndOddHeaders` in one undo unit. Header and footer chrome in both adapters can toggle different even and odd pages. |
| Section vertical alignment (vAlign) | No | No | Full | Round-trips; page content stays top-aligned. |
| Page background color/image (w:background) | No | No | Preserved | Not rendered and not editable. Authored background markup and relationships are preserved. |
| Page number format (pgNumType) | No | Partial | Full | Section numbering start, format, chapter style, and chapter separator parse and serialize. PAGE fields in headers and footers honor the authored start and format, for example lowerRoman. A non-decimal format wins over a numeric picture switch, because a roman or alphabetic page number has no digits to place. NUMPAGES and SECTIONPAGES are decimal unless the field states a picture. There is no authoring UI for pgNumType yet. |
Tracked changes, comments, and notes
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Tracked changes (insert, delete, format) | Full | Full | Full | A full revision model, including structural changes to paragraph breaks, paragraph properties, and table rows and cells. Paragraph marks stay hidden until Review → Show paragraph breaks is enabled, independently of revision selection. Tracked manual line-break marks use their revision color and decoration. The toggle also shows ordinary paragraph ends (¶) and manual line breaks (↵), without marking automatic line wraps, page breaks, or column breaks. Adjacent text and paragraph-break insertions or deletions by the same author form one decision. Break-only cards show the grouped break count. Formatting revisions stay in the page balloon by default, including proofing-language changes on empty paragraph marks; hosts can opt into sidebar cards. Change bars remain visible wherever the paragraph is, including table cells. A mark that one author inserted and another proposed removing carries both decisions. A tracked insert or delete around a field result paints as tracked, not as ordinary text. Tracked deletion and replacement refuse simple fields with nested fields or other result containers; direct result runs remain supported. Attribution is drawn in All Markup only, as in Word. The resolved views drop the attribution and merge the paragraphs the decision merges, so No Markup shows the document as accepting every change would leave it. Review offers Next/Previous Change, atomic Accept/Reject All Changes across document stories, and All Markup/No Markup/Original views. Original restores prior run and paragraph formatting; prior table, row, cell, and section formatting remains unsupported. The Reviewers menu can hide individual authors without mutating the DOCX. The setTrackedChangesFilter API accepts a predicate over complete revision items, so a host can combine author, date, kind, range, and other revision metadata. Excluded content, moves, paragraph marks, and table-row revisions can render as temporarily accepted or rejected without changing saved OOXML. Suggesting requires a configured author; an authorless request reports a configuration error and disables the Suggesting menu item. Suggesting mode records a formatting change rather than applying it outright: a run gets w:rPrChange, a paragraph mark gets w:pPr/w:rPr/w:rPrChange, and paragraph properties get w:pPrChange, so reject restores what the change replaced, and one press is one card however many runs it covers. Lists, indent level, tab stops, and table properties changed in the editor are applied without a record. A document that sets w:doNotTrackFormatting gets no formatting records. Painted markup follows Word’s by-author view by default — one color per author, matched by the review cards — and named authors can take a color, a background, class names, and an avatar of their own. The output opens cleanly in Word’s review pane. |
| Accept / reject changes (UI + API) | Full | Full | Full | Accept or reject one shown change in the sidebar, or through acceptReviewItem and rejectReviewItem. Reviewer visibility is view-only; hidden authors are excluded from the review item list and therefore from bulk operations over that list. The automation object model adds revision.accept(), revision.reject(), revisions.acceptAll(), and revisions.rejectAll(). The sidebar has no bulk control, so call the per-item command for every shown item. |
| Comments (threads, replies, resolve) | Full | Full | Full | Threaded comments with replies and resolve/reopen in the review rail. React hosts use `@docx-editor.dev/pro/react`; Vue hosts use `@docx-editor.dev/pro/vue` with the same engine commands. |
| Programmatic redlining (code-proposed tracked changes) | Full | Full | Full | The automation object model writes Word-native tracked changes. It works over DOCX bytes on a server, or over an editor open in a page. |
| Tracked moves (move from/to) | Partial | Full | Full | Imported moves render distinctly from insert and delete, and they round-trip. |
Fields, links, and table of contents
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Hyperlinks (external) | Full | Full | Full | Insert, edit, and remove a link with Ctrl+K, Cmd+K, or the toolbar. Targets are allowlisted: http, https, mailto, tel, and ftp. Any other target renders inert and still round-trips. A HYPERLINK field, complex or w:fldSimple, is a live link too: its target passes the same allowlist, and the link panel shows it read-only. Links in footnote and endnote text work the same way. Links in headers, footers, and anchored text boxes resolve through their own part. You can edit or remove header and footer links with Ctrl+K while editing their story. Secondary-story anchors remain inert and do not open. Opening a document never requests a link target, because activation needs an explicit gesture. |
| Bookmarks & internal links | Partial | Full | Full | Internal links jump to their bookmark and move the caret. This includes a target on a page the editor has not painted yet. Creating and renaming bookmarks is deferred. |
| PAGE / NUMPAGES / SECTIONPAGES fields | Partial | Partial | Full | PAGE, NUMPAGES, and SECTIONPAGES project as a complex field or w:fldSimple. They evaluate in headers and footers and in the body flow, body tables included. PAGE respects the section pgNumType start and format. Fields inside an anchored header or footer text box also project, as does a page field nested inside another field — simple or complex, such as STYLEREF — up to four levels deep, evaluated per page. React header and footer chrome can insert them, including Page X of Y. A numeric picture switch, for example PAGE \# 0#, renders the computed value. Pictures support digit placeholders, a grouping comma, and literal text. In a header or footer the picture always renders the computed value, so a result cached in the file never reaches the page; in the body a non-empty cached result still wins until the field is updated. A body field with no cached result paints a placeholder that document layout substitutes per page. Without a picture, a multi-digit body value keeps the one-digit measured width, so mid-line following text does not reflow; with one, the picture sets that width, and a value wider than the picture overflows it the same way. |
| Table of contents | Partial | Full | Full | Insert a body TOC from the shared Insert menu, then refresh it from the document headings. A refresh can update the page numbers only. Tab leaders, section-formatted page numbers, and bookmark links all work. The generated rows are read-only navigation links. |
| REF and NOTEREF cross-references | Partial | Partial | Full | REF resolves bookmark text and numbered paragraph references in the body, footnotes, and endnotes. The editor supports the \r, \w, \n, \t, \h, and \* MERGEFORMAT switches. The \r switch uses the same full-context number as \w, and \t needs a numbering switch. Bookmark text stops at the target paragraph boundary. NOTEREF resolves bookmarked note numbers with section formats and eachSect restarts. Unsupported switches, missing targets, bullet targets, eachPage note restarts, and custom note marks keep the saved result. Save refreshes calibrated, writable body and note results as one undo step. Header, footer, and text-box results keep their saved values. |
| AUTONUM field numbers | No | Partial | Full | AUTONUM, AUTONUMLGL, and AUTONUMOUT generate separate document-order sequences. They do not restart by heading context. The \* switch supports Arabic, alphabetic, Roman, ordinal, cardinal text, ordinal text, and hexadecimal formats. The \e switch removes the trailing period. Unsupported switches produce no generated value. Save does not add result runs. |
| Other field codes (DATE, SEQ, MERGEFIELD...) | No | Partial | Preserved | The saved result displays for a complex field and for w:fldSimple. Field codes round-trip unchanged. SYMBOL renders its character with the requested font and size. MACROBUTTON and GOTOBUTTON render display text without running the macro or jump. TITLE, AUTHOR, SUBJECT, KEYWORDS, LASTSAVEDBY, COMMENTS, and matching DOCPROPERTY fields render sanitized document metadata. DATE-valued properties stay inert. DATE, TIME, FILENAME, SEQ, LISTNUM, and EQ do not calculate a new value. The editor never runs macros, DDE instructions, or external include instructions. |
| Citations & bibliography | No | No | Preserved | CITATION and BIBLIOGRAPHY fields stay inert, and the b:Sources store is preserved. Citation evaluation and editing are not supported. |
| Legacy form fields (FORMTEXT, FORMCHECKBOX, FORMDROPDOWN) | Partial | Full | Preserved | FORMTEXT supports whole-field selection on click, partial text edits, select-then-delete at field boundaries and whole-field replacement in unprotected documents, and a shared React/Vue options dialog through double-click or the keyboard-accessible Edit field context action. The dialog supports regular text, number, and date types, maximum length, listed formats, and fill-in enabled. Native selection highlighting and accessible status distinguish a whole field from a caret. In documents protected for forms, plain text results remain fillable and Tab selects the next enabled text field. FORMCHECKBOX renders its checked or default state from w:ffData, and an explicit w:size sets the glyph size. FORMDROPDOWN renders the cached result, or the selected list entry when the file caches none. Field markers, instructions, and w:ffData round-trip, and tracked edits survive. Form-field shading applies unless w:doNotShadeFormData is set. Protected filling enforces maximum length, truncates pasted text to the remaining capacity, and applies supported value formats on exit or save. Save uses the original input locale and rejects invalid pending values without clearing the input. Supported numeric filling and formatted numeric defaults include mixed text, dollar signs, grouping, and accounting parentheses. Unformatted numeric defaults preserve raw text; formatted numeric defaults store their formatted value. The editor locale controls regional Gregorian date input independently of field output formatting, including dotted dates, year-first dates, and locale digits. Locale changes preserve existing dates. Invalid numeric/date fill input opens a shared alert; acknowledgement clears the invalid result with undo support. Full parity across Word locales and input grammars is not established. Computed input types and unlisted format pictures remain preserved without protected filling. Checkbox and dropdown interaction are not built. Results with nested fields, revisions, or non-text structure cannot use the default-text dialog or protected filling. |
Document structure and content controls
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Content controls (SDT): block, inline | Partial | Full | Full | Block, inline, row, and cell controls are typed and addressable in every story, table cells, headers, footers, and note bodies included. A control around a row or cell lays out as that row or cell, and keeps its column, span, and row semantics. Find, create, fill, and remove a control by tag, title, or file id from the document object model. The open editor authors a control too, over the selection or at the caret, as one undoable step: a caret insertion arrives empty and showing its prompt, the way it does in Word. Content is editable, and tag, title, and lock are writable through the API, but they have no toolbar chrome. All four `w:lock` modes are enforced against what an edit would change, and an enclosing lock wins over an inner one. The editor resolves a write against every control it would land in, so filling an outer control cannot write into a locked or bound control nested at its edge. A lock protects the control and its content, not the rest of the document. Under `w:documentProtection w:edit="forms"` only control content is editable. Picture, repeating-section, custom-XML-bound, and docPart gallery controls are preserved as authored rather than typed; the editor refuses an edit inside a bound control, but it allows you to remove the control. |
| Repeating section controls | No | Full | Full | Repeating-section markup is preserved and rendered. Item add and remove operations and section configuration edits are unsupported. |
| Dropdown, checkbox & date controls | Full | Full | Full | Each control accepts only the value its own type allows. A dropdown must name an item it declares, and a combo box also takes free text. A date validates an ISO instant and writes both `w:fullDate` and the formatted text. A checkbox writes its declared glyph and its state together. Editor checkbox toggles use MS Gothic when the state omits its font. The first write replaces a literal prompt whole, so clearing the value later leaves the control empty. A `w:temporary` control removes its own wrapper on the first edit and keeps the content. |
| Custom XML parts & data binding | No | No | Preserved | customXml parts and w:dataBinding round-trip with structural fidelity. The editor does not evaluate a binding. |
| VBA macros | No | No | Preserved | The editor never executes a macro, by design. The vbaProject part survives open and save. |
| OLE & embedded objects | No | No | Preserved | The editor never executes or renders OLE. OLE markup and embedded binaries are preserved through editing and save. |
| Document protection & editing restrictions | Partial | No | Preserved | Protection settings round-trip. Forms protection is enforced: only addressed control content stays editable, and the rest of the document is read-only. Other protection modes are not enforced, and inline permission ranges may be dropped. |
Collaboration, languages, and editing
| Feature | Editing | Rendering | Round-trip | Notes |
|---|---|---|---|---|
| Real-time collaboration | Partial | Partial | Preserved | Yjs replicates text, formatting, document structure, review content, tables of contents, notes, headers, footers, drawings, and custom nodes. Presence includes participants, carets, and cross-paragraph selections. Each participant can undo only their edits. One simultaneous run-formatting split converges without duplicate text. A later split after one concurrent run-formatting round can duplicate text. Replicas still converge. Use WebRTC, Hocuspocus, or another Yjs 13 provider. Optional offline editing merges buffered changes after reconnection. Applying an edited ProseMirror document is unavailable while a replica is attached. |
| Find & replace | Partial | Full | Full | Searches the body, headers, footers, footnotes, and endnotes, including table cells and saved field results. Find also searches anchored text boxes in the body, headers, and footers. Inline text boxes and text boxes in notes are excluded. Selecting a text-box match selects its drawing; the content remains read-only. |
| Rich copy/paste (HTML clipboard) | Partial | Full | Full | Copy writes plain text and HTML with an embedded document fragment. Pasting that fragment restores styles, lists, tables, links, images, footnotes, and endnotes. External HTML does not restore notes. Sections, headers, footers, and comments do not travel on the clipboard. Suggesting mode and non-body scopes use plain-text paste. |
| Undo / redo | Full | Full | Full | |
| Editor UI in 10 languages | Full | Full | Full | de, en, fr, he, hi, id, pl, pt-BR, tr, and zh-CN via @docx-editor.dev/i18n. |
| Automatic fit / responsive zoom | Full | Full | Full | The default zoom mode is `auto`: it fits the page width between 50% and 100%. A container narrower than a Letter sheet shrinks the document instead of overflowing. Chrome that pads the scroll container, such as the navigation pane or the review rail, recomputes the fit. A host can pin a fixed scale with `zoom` or `zoomMode={{ type: 'fixed' }}`, or ask for uncapped fit-width. The toolbar ladder and the Ctrl+= and Cmd+= shortcuts use the same engine-owned mode. |
| Document automation object model | Full | Full | Full | A batching object model shaped after a documented subset of the Word JavaScript API. The server entry works over bytes and reports exceeded resource limits with typed errors. The browser entry works over an open editor. It ships no model integration, tool catalog, or MCP transport. |
Important drawing limits
The matrix remains the source of truth for support status. These drawing limits often affect document evaluation.
| Feature | Rendering | Editing | Round-trip |
|---|---|---|---|
| Anchored text boxes | Shows read-only content inside the authored extent. Linked chains, autofit, and rotation can clip or use placeholders. | No | Preserved |
| Drawing shapes | Renders solid rectangles, ellipses, bounded polygons, and groups. Other shapes use a placeholder. | No | Preserved |
| WMF and EMF | Rasterizes supported files. Other files keep their extent with a placeholder. | No | Full |
Rendering and pagination
The editor renders opaque solid Word 2010 text outlines with explicit RGB colors. Other text effects remain preserved; the text-effects matrix lists the rendering limits. PDF export does not paint these outlines.
The editor calculates document layout without browser flow layout. It uses document fonts, themes, section geometry, margins, and Word units.
The layout result controls line and page breaks. The editor paints that result as DOM text, not a canvas bitmap.
Usable font bytes are required for Word-accurate text measurement. See Fonts and measurement.
The configured font resolver also receives faces used by SYMBOL fields and numbering markers. Your host must supply usable font bytes for those faces when they are unavailable locally. Unused numbering definitions do not add font requests.
East Asian layout keeps punctuation, graphemes, and full-width number groups together across formatting changes. Justified lines distribute inter-character spacing through the same geometry used for paint and caret placement.
East Asian font hints select the document's East Asian face for supported punctuation, symbols, Greek, and Cyrillic ranges. Combining marks and joined emoji keep their base character's slot across text runs. Explicit symbol fonts retain their selected face.
Existing document settings control kinsoku, Japanese strict rules, custom language-specific break restrictions, Korean character wrapping, punctuation overflow, and punctuation or kana compression. Compression uses deterministic advance reductions. Font-specific optical compression is not modeled. The feature matrix lists the support limits for East Asian typography.
For pipeline details, see Architecture. Test your documents in the live demo.
Round-trip contract
A DOCX file is a ZIP package with XML parts and binary payloads.
| Content | Save behavior |
|---|---|
| Modeled OOXML | Serializes from typed document nodes. |
| Unmodeled XML elements and attributes | Re-emits generic nodes in place. |
| Legacy VML, custom XML, and add-in markup | Preserves structural content. |
| Media, VBA projects, embedded fonts, and OLE binaries | Copies package payloads without modification. |
| Relationship IDs, bookmark names, style IDs, and numbering definitions | Keeps references intact. |
| Tracked changes | Writes Word w:ins and w:del revisions. |
| Theme colors | Keeps theme references instead of flattening them to RGB values. |
The contract protects semantic meaning and structure. It does not promise byte identity for rewritten XML parts.
Continuous integration checks real documents with a canonical tree fingerprint and a save-and-reopen semantic digest. Focused tests cover revisions, fields, hyperlinks, content controls, and browser editing.
If untouched content is lost or reinterpreted, report a round-trip issue with the source document.
Security and data flow
| Concern | Behavior |
|---|---|
| Browser uploads | The editor package does not upload documents or call a conversion service. |
| Macros | The editor preserves VBA payloads but never executes them. |
| OLE | The editor preserves OLE payloads but never executes or renders them. |
| Calculated fields | Supported calculated fields update display text only. Macros, DDE, and external includes remain inert. |
| Hyperlinks | Allowlisted targets open only after a user gesture. |
| Server editing | Your host controls where DOCX data runs. |
| Browser automation | Controls an editor already in the page. |
| External artificial intelligence | @docx-editor.dev/editor-api includes no model integration or transport. |
Your application controls any data sent to another service or model.
Bundle and performance
| Area | Behavior |
|---|---|
| Core exports | Subpath exports can tree-shake independently. |
| Engine copies | Adapters use core as a peer dependency to resolve one engine copy. |
| Initial bundle | You can lazy-load the editor with your framework. |
| Layout work | Per-block caches avoid measuring unchanged blocks again. |
| Benchmarks | No published benchmark represents every document. Test your own files. |
License and API stability
| Package or policy | Terms |
|---|---|
@docx-editor.dev/core, @docx-editor.dev/react, @docx-editor.dev/vue, and @docx-editor.dev/i18n | Apache 2.0 |
@docx-editor.dev/fonts | Apache-2.0 AND OFL-1.1 AND LicenseRef-GUST-Font-License |
@docx-editor.dev/editor-api | EigenPal Pro License |
@docx-editor.dev/pro | EigenPal Pro License |
| Versions | Semantic Versioning with one fixed version group |
| Public API | CI checks generated API Extractor snapshots |
| Contributions | Require a one-time Contributor License Agreement |
The Pro packages are licensed under the EigenPal Pro License, and you can compare and buy license and support levels on the pricing page.
Next steps
- Quickstart: Load, edit, and save a DOCX file.
- Architecture: Review the engine pipeline.
- Fields and cross-references: Review field evaluation limits.
- Tracked changes: Review revision behavior.