@tiptap-pro/extension-export-docx changelog

Changelog for @tiptap-pro/extension-export-docx

0.19.0

Minor Changes

  • Add ordered list numbering format support to DOCX export.

    • numberingFormats?: NumberingFormatDefinition[] option on ExportDocx / exportDocx() / ConvertConfig. Each entry is a multilevel numbering definition (per-level base style, marker template, indent, alignment, font) that the exporter resolves against the numberingFormat string attribute on the outermost <ol> of each multilevel list. Unknown / missing ids fall through to the package's default 'ordered-list' numbering — consumers who don't opt in see zero behavior change.
    • New types NumberingFormatDefinition and NumberingLevelDefinition. Word's <w:lvlText> grammar (%N references the counter at level N) is used verbatim. No preset formats are shipped — define your own.
    • LevelFormat, IRunOptions, and PositiveUniversalMeasure are re-exported from docx so consumers can build definitions without a second import.

    Editor-side wiring (the Tiptap attribute extension and the editor-preview CSS) is the consumer's responsibility — a reference implementation is in demos/src/Extensions/ExportDocxOrderedListNumbering/React/.

    Also fixes a pre-existing bug where nested ordered lists each allocated their own DOCX numId, fragmenting counter chains across nesting boundaries. The outermost list's instance id is now threaded through every nested convertOrderedList call so a multilevel list shares one numId and Word's per-level counter logic works as expected.

0.18.0

Minor Changes

  • Add customNodeDsl — a JSON-native way to describe how custom Tiptap nodes should render into DOCX.

    The existing customNodes API is great inside the editor, but it relies on JavaScript functions, which can't be sent over HTTP. That has historically meant that the DOCX REST API had no way to render application-specific content like callouts, mentions, or hint boxes. customNodeDsl closes that gap with a small, serializable language that produces identical output to the function API and travels cleanly over the wire.

    What's in the box:

    • A versioned wire format (dslVersion: "1.0") with seven render-node shapes (element, $children, $text, $fragment, $if, $switch, null) and a closed element catalog (Paragraph, TextRun, ExternalHyperlink, Table, TableRow, TableCell, PageBreak).
    • A typed value-expression layer — $ref for PM-node attributes, $template for string interpolation, $op for typed compute, $unit for the same unit helpers the function API ships (pointsToTwips, pixelsToHalfPoints, normalizeColor, …), plus $switch/$if for conditional rendering. No eval, no Turing-completeness, no surprises.
    • Full marks integration — MarkPolicy on $children/$text and applyMarks on inline elements, both reusing the same standard mark pipeline as the rest of the converter, plus per-mark overrides and disable for fine-grained control.
    • A clean override-precedence ladder so DSL props compose predictably with cssStyles, styleOverrides, and the existing *Overrides bundles.
    • Source-mapped errors (every error carries dslPath and, at runtime, nodePath + nodeType) and configurable resource caps via the new customNodeDslLimits option.
    • Both APIs coexist on the editor — when the same node type appears in both customNodes and customNodeDsl, the function definition wins and a single console.warn is emitted per export. Existing function-based customers see zero behavior change.

    Refactoring under the hood: the mark-to-TextRun translation in convertTextNode was extracted into reusable computeMarkFormatting and buildTextRun helpers so the DSL pipeline can drive marks identically without synthesizing fake PM nodes. This is a behavior-preserving change — every existing test passes unchanged.

    The new CustomNodeDsl, CustomNodeRule, RenderProgram, RenderNode, ValueExpr, MarkPolicy, ApplyMarksPolicy, and CustomNodeDslLimits types are exported from the package root, alongside the compileCustomNodeDsl, DslCompileError, and DslRuntimeError runtime helpers for advanced users running the extension on their own server.

    TypeScript builder under a tree-shakeable subpath. Authoring rules in TypeScript? Import the fluent builder from @tiptap-pro/extension-export-docx/dsl and let the type system catch containment violations at edit time:

    import {
      childrenInline,
      docxNode,
      paragraph,
      ref,
      template,
      textRun,
    } from "@tiptap-pro/extension-export-docx/dsl";
    
    const dsl = {
      dslVersion: "1.0",
      nodes: [
        docxNode("hintbox")
          .block()
          .emit(
            paragraph({ style: "Hintbox" }).children(
              childrenInline({ marks: "default" })
            )
          )
          .toJSON(),
        docxNode("mention")
          .inline()
          .emit(
            textRun({
              text: template("@{node.attrs.label}"),
              color: ref("node.attrs.color", {
                default: "4472C4",
                transform: "hexNoHash",
              }),
            }).applyMarks("node")
          )
          .toJSON(),
      ],
    };

    What you get:

    • Autocomplete on every element prop. paragraph({ … }) suggests style, alignment, spacing, border, shading, … exactly the field set the DSL compiler validates.
    • Compile-time containment safety. paragraph().children(childrenBlock()) is a TypeScript error — paragraphs only accept inline children. table().rows(paragraph()) is also an error — Table.rows requires TableRow builders. The errors fire at edit time, not at runtime.
    • Required-prop checking. externalHyperlink({}) is a TypeScript error: the link prop is required.
    • Wire-format compatibility. .toJSON() produces the exact same JSON the Custom-nodes DSL compiler accepts. Same payload works inside the editor, in a Node.js server, or as a customNodeDsl field over the convert REST API.
    • Tree-shakeable. The builder ships under a separate ./dsl subpath in the package's exports field — callers who never touch it don't pay for it.

    The full builder surface (docxNode, paragraph, textRun, externalHyperlink, table, tableRow, tableCell, pageBreak, childrenInline / childrenBlock / childrenTableRow / childrenTableCell, iff / switch_ / fragment / textOp, ref / template / op / unit / switchValue / marks, plus all per-element prop interfaces) is documented at Custom-nodes DSL builder.

    Inline decoration on Paragraph. The DSL Paragraph element gains border and shading props that mirror the IParagraphOptions shape on docx.js. Custom nodes that previously needed a named styleOverrides.paragraphStyles entry purely to carry decorative chrome (boxes, callouts, hint boxes) can now express it inline on the DSL element — no parallel style declaration, no round-trip indirection. The named-style label still works for round-trip identity (<w:pStyle> survives whether or not it's declared in styles.xml), so existing payloads keep behaving the same.

    See the new Custom-nodes DSL docs for the JSON spec, worked examples (hintbox, mention, callout box, code block, custom link), and the precedence model — and the DSL builder docs for the TypeScript-ergonomic equivalent.

  • Add a pageColor option to ExportDocx and convert() that writes the DOCX w:background element, letting Word display the document with a colored page. Accepts any CSS color the package's normalizeColor helper resolves (hex, rgb() / rgba(), named colors); "transparent" and unresolvable values omit the element. Note that Word does not print page background by default — users must enable "Print background colors and images" under Word Options for the color to appear in printed output or PDF exports.

  • Configurable header/footer placeholders with end-to-end DOCX round-trip support.

    • Pages: new placeholders option to rename the built-in {page} / {total} tokens or disable substitution. Defaults preserve existing behavior.
    • ExportDocx: header/footer text now translates registered tokens into live Word PAGE / NUMPAGES fields instead of literal text. When the Pages extension is installed, the export auto-picks up its placeholders config so the editor preview and the exported .docx stay aligned. Body content is never substituted.
    • ImportDocx: the importer now forwards Pages.options.placeholders to the convert service so Word PAGE / NUMPAGES fields come back as text tokens that match your active Pages registry — {page} / {total} by default, or your rename. The editor preview substitutes the imported tokens natively, with no .replace() step and no placeholders: { total: 'numpages' } workaround. Pass placeholders: false on the command to opt out, or placeholders: { page, total } to override the editor's registry per-call.

    The convert service exposes the same placeholders field on /import/docx and /export/docx for direct REST API callers who want the same control without an editor.

0.17.0

Minor Changes

  • Add export docx missing overrides for header and footers
  • DOCX export now serializes subscript and superscript text marks. Content like H₂O and x² preserves its formatting on export, where it was previously emitted as plain text.

Patch Changes

  • Update fast-xml-parser to patch vulnerabilities CVE-2026-33349 and CVE-2026-41650

0.16.1

Patch Changes

  • Fix image dimensions in DOCX export. Images were previously shrunk to 75 % of their intended size because pixel values were converted to points before being passed to docx's ImageRun.transformation, which already expects pixels at 96 dpi.

0.16.0

Minor Changes

  • Add support for paragraph, table, text run, table cell, and image overrides in header and footer content. Also add a new headerFooterOverrides option for styling headers and footers separately from the body.

    • convertHeader and convertFooter now accept these options: customNodes, pageSize, pageMargins, tableOverrides, tableCellOverrides, paragraphOverrides, textRunOverrides, imageOverrides. Before, header and footer content was always converted with default values, so the overrides did not work.
    • New option headerFooterOverrides in ExportDocxOptions. You can use this to style header and footer content different from the body. Each field replaces the body-wide value, it does not merge. If a field is not set, it uses the body value. This only works for headers and footers that come from the Pages extension.
    • Fix: when you set paragraphOverrides.spacing.before or spacing.after, the values were lost because the code overwrote the spacing object with only spacing.line. Now before, after, and line all work together.
  • Add header and footer properties to the pageMargins option, controlling the distance from the page edge to the header/footer. When the Pages extension is configured, these values are auto-derived from headerTopMargin and footerBottomMargin; caller-provided values always take precedence.

    For extension-export-pdf, extension-export-doc, and extension-export-odt, full end-to-end support requires the Tiptap convert service to be on a version that accepts the new pageMargins.header/footer fields and ships an updated @tiptap-pro/extension-export-docx.

0.15.5

Patch Changes

  • Render {page} and {total} tokens in plain-text headers and footers as live PageNumber.CURRENT / PageNumber.TOTAL_PAGES fields, so exported DOCX files show the actual page number and total page count instead of the literal token strings.

0.15.4

Patch Changes

  • Inline images inside a paragraph now inherit the paragraph's formatting (alignment, line spacing, paragraphOverrides, heading level, list numbering) in the DOCX export. Previously these attributes were dropped because the image was emitted as its own wrapper paragraph. Block-level images (siblings of paragraphs) and the public convertImage API are unchanged; a new convertImageRun helper is exported for callers that need the raw inline run.

0.15.3

Patch Changes

  • Fix DOCX rendering in viewers that don't support universal measures by converting page dimensions and margins to numeric twips, and add explicit document defaults for font size, font family, and language settings

0.15.2

Patch Changes

  • Minor bugfixes & improvements

0.15.1

Patch Changes

  • fix: do not overwrite global default styles

0.15.0

Minor Changes

  • Add page break support to DOCX export. The pageBreak node is now converted to a <w:br w:type="page"/> element, producing a standard Word page break in the exported document. A new convertPageBreak function is also publicly exported for use in custom node conversion pipelines.

0.14.0

Minor Changes

  • Fix table cells only rendering paragraphs by delegating to the central node converter, enabling support for lists, headings, images, blockquotes, and nested tables inside table cells

0.13.0

Minor Changes

  • Extend DOCX export with deep customization overrides for paragraphs, text runs, table cells, and images.

    tableOverrides (new)

    Allows overriding any ITableOptions property except rows. Values are spread last, so user-provided table-level properties (borders, margins, layout) win over computed defaults.

    paragraphOverrides (new)

    Accepts any IParagraphOptions property except children. Spread first as base defaults — per-node computed values like alignment, spacing, heading level, and list numbering override them. Applied to all paragraph creation paths: standard paragraphs, headings, blockquotes, bullet lists, ordered lists, and list items.

    textRunOverrides (new)

    Accepts any IRunOptions property except text. Spread first as base defaults — per-mark formatting (bold, italic, underline, font family, font size, color, highlight, etc.) overrides them. Useful for setting a default font or size across the entire exported document. Applied to all text run creation paths including styled paragraphs (e.g. blockquotes) and standard content.

    tableCellOverrides (new)

    Accepts any ITableCellOptions property except children. Spread first as base defaults — per-cell computed values like width, column span, and width type override them. Useful for applying consistent cell shading, vertical alignment, or border styles across all table cells.

    imageOverrides (new)

    Accepts any IImageOptions property except data, type, and fallback. Spread last so user-provided values (e.g. custom transformation dimensions) win over the intrinsic dimensions detected from the image buffer. SVG fallback data is always preserved regardless of overrides.

    Usage example

    editor.commands.exportDocx({
      onCompleteExport: (result) => {
        /* ... */
      },
      exportType: "blob",
      paragraphOverrides: {
        spacing: { after: 200, before: 100 },
      },
      textRunOverrides: {
        font: "Arial",
        size: 24, // 12pt in half-points
      },
      tableCellOverrides: {
        shading: { fill: "F0F0F0", type: ShadingType.SOLID },
      },
      imageOverrides: {
        transformation: { width: 400, height: 300 },
      },
    });

    Note: All override objects use shallow spreading, not deep merging. When overriding nested properties like spacing or transformation, provide the complete nested object to avoid undefined fields.


    Node attribute inference (new)

    The DOCX export now respects node-level attributes set by the editor instead of always computing values from scratch.

    Image width/height from node attrs

    When an image has been resized in the editor (via ResizableNodeView), the user-set width and height attributes are now used for the exported dimensions instead of the intrinsic image dimensions. If only one dimension is set, the other is computed proportionally from the intrinsic aspect ratio. Priority chain: imageOverrides.transformation > node.attrs.width/height > intrinsic dimensions.

    Image alt text

    The alt attribute on image nodes is now mapped to the docx altText property (DocPropertiesOptions.name), providing accessibility metadata in the exported document.

    Table cell colwidth

    When table columns have been resized in the editor, the per-cell colwidth attribute (pixel array) is now used to compute precise column widths in the export. Falls back to even distribution when colwidth is not set.

    Table cell rowspan

    The rowspan attribute on table cells is now supported. Cells spanning multiple rows are correctly exported with the rowSpan property in the docx output.

    Paragraph textAlign: 'justify'

    Justified text alignment is now correctly mapped to AlignmentType.JUSTIFIED in the export. Previously, 'justify' fell through to left alignment.

    Text run backgroundColor

    The backgroundColor attribute on the textStyle mark is now exported as solid character shading on text runs. Previously, inline background colors were silently dropped.

  • Initial beta point for export and pages packages

3.0.0-beta.31

3.0.0-beta.30

Patch Changes

  • Bumped Tiptap and Hocuspocus Dependencies to most recent version

3.0.0-beta.29

3.0.0-beta.28

3.0.0-beta.27

3.0.0-beta.26

3.0.0-beta.25

Patch Changes

  • Bumped @tiptap and @hocuspocus dependencies

3.0.0-beta.24

Patch Changes

  • Bump tiptap and hocuspocus dependencies

3.0.0-beta.23

3.0.0-beta.22

Patch Changes

  • upgraded hocuspocus and tiptap dependencies

3.0.0-beta.21

3.0.0-beta.20

Patch Changes

  • Bumped tiptap and hocuspocus dependencies

3.0.0-beta.19

3.0.0-beta.18

Patch Changes

  • updated tiptap and hocuspocus dependencies

3.0.0-beta.17

3.0.0-beta.16

Patch Changes

  • Updated tiptap packages

3.0.0-beta.15

Major Changes

  • Updated all tiptap dependencies

0.1.0

Initial release of extension-export-docx as beta version.