Description

Export notes to Microsoft Word (.docx) with images, real bordered tables, math and diagrams.

Additional Information

Links:
Maintainers: comonduck
Version:1.0.0
Minimum app version:3.0
Downloads: This version:30
Last updated:2026-08-07T00:34:14Z

2docx — Word (.docx) export for Joplin

Exports Joplin notes to real Microsoft Word documents. Everything is generated in JavaScript inside Joplin, so there is no Pandoc, LibreOffice or other external tool to install — drop in the plugin file and export.

It was written to fix the two things that most Markdown-to-Word paths get wrong:

  • Images are embedded. Joplin resources (:/resource-id), external URLs, data: URIs and local files all end up inside the .docx. Formats Word cannot read, such as WebP, are converted to PNG on the way in.
  • Tables keep their borders. Tables are written as real Word tables with visible gridlines, a shaded header row that repeats across page breaks, per-column alignment and content-aware column widths.

Installing

From Joplin

Tools → Options → Plugins, search for 2docx, press Install and restart Joplin.

From the plugin file

  1. Download com.github.comonduck.2docx.jpl from the releases page.
  2. In Joplin, open Tools → Options → Plugins.
  3. Press the gear icon next to Manage your plugins and choose Install from file.
  4. Select the .jpl and restart Joplin.

You can also copy the file straight into your plugin directory and restart:

Platform Directory
Linux ~/.config/joplin-desktop/plugins/
Windows %USERPROFILE%\.config\joplin-desktop\plugins\
macOS ~/.config/joplin-desktop/plugins/

From source

git clone https://github.com/comonduck/joplin-plugin-2docx.git
cd joplin-plugin-2docx
npm install
npm run dist        # writes publish/com.github.comonduck.2docx.jpl

Using it

Right-click a note → Export → "DOCX - Word Document (docx)", then choose where to save. The Save dialog is pre-filled with the note's title.

That is deliberately the only place it appears. Exporting one note at a time is what this plugin is for, so it stays out of File → Export all — that menu exports your entire database, which for a Word exporter means dozens of files you did not ask for. Joplin also hides the entry when more than one note is selected.

Joplin builds the menu label itself, as FORMAT - description, which is why the entry reads "DOCX - Word Document (docx)".

Settings

Tools → Options → 2docx (Word export)

Setting Default Notes
Page size A4 A4, Letter or Legal
Landscape orientation off
Page margin (mm) 25
Body font Sarabun Applied to Latin and complex-script text. Empty means "let Word decide".
Heading font empty Falls back to the body font
Code font Consolas
Body font size (pt) 11
Line spacing 1.15 Thai and other tall scripts read better at 1.3+
Treat single line breaks as line breaks on Matches Joplin's default display
Add the note title as a heading on
Table style Grid Grid, Minimal (horizontal rules) or Plain
Maximum image width 100% Of the text width. Images already smaller keep their size.
Download and embed external images on Turn off to export with no network access
Insert a table of contents off
Add page numbers in the footer on
Convert $math$ to Word equations on
Render mermaid diagrams as images on

Thai and other complex scripts

Word stores two parallel sets of character formatting: one for Latin text and one for complex scripts — Thai, Arabic, Hebrew, Devanagari and others. Bold, italics and font size applied only to the Latin properties are silently ignored on Thai characters, which is why Thai text so often comes out of converters unstyled.

2docx writes both sets (w:b/w:bCs, w:i/w:iCs, w:sz/w:szCs, and w:rFonts with the cs attribute) on every run, so Thai bold and italics render properly.

The Body font default is Sarabun, a free Google font that covers Thai and Latin and is available in Google Docs. If you do not write Thai, set it to whatever you prefer, or clear it to use Word's own default. Whichever font you choose has to be installed on the machine that opens the document.

What gets converted

Markdown Result in Word
Headings ####### Heading 1–6 styles, so they drive the navigation pane and the table of contents
bold, italic, strikethrough, ==highlight==, ++inserted++ Matching character formatting
super^script^, sub~script~ Superscript / subscript
Bullet and numbered lists Real Word lists, nested up to 9 levels, restarting correctly and honouring start values
- [ ] / - [x] ☐ / ☒ checkboxes
Tables (including multiline, colspan and rowspan) Word tables with borders and repeating headers
Images Embedded, scaled to fit the text width, aspect ratio preserved
<img src=":/…" width="275"> Also embedded, at the size you set. Joplin rewrites any image you resize in the editor as an HTML tag rather than Markdown, so these matter more than they look.
<div align="center">, <p style="text-align: right">, <center> Applied to the paragraph, together with any <i>, <b>, <a> or <img> inside. Markdown has no alignment syntax, so raw HTML is the way to centre a figure caption — and it is the only thing that gets centred: ordinary paragraphs are always left-aligned, as in the editor and in Joplin's PDF export.
Links Clickable hyperlinks; links between exported notes become internal links
> quotes Indented with a vertical rule, nestable
Fenced code Shaded, bordered monospace block with an optional language label
$math$, $$math$$ Native, editable Word equations (via KaTeX → MathML → OMML), not pictures
```mermaid Rendered diagram image
Footnotes Real Word footnotes
--- Horizontal rule
Definition lists, abbreviations Bold term with indented definition

Known limitations

  • One note per export, by design — see Using it above.

  • Mermaid diagrams need a brief dialog. Mermaid has to measure text in a laid-out browser window to size its diagrams, and Joplin hides inactive plugin panels with display: none, where every measurement returns zero. So when a note contains diagrams, a small "Rendering diagrams…" dialog appears for a moment and closes itself. If you dismiss it, or rendering fails, the diagram is exported as a code block instead — the export never fails because of a diagram.

  • SVG images are embedded as SVG. Word 2016 and later display them; older versions show a blank placeholder, because rasterising an SVG needs a renderer the plugin does not have.

  • Raw HTML is not rendered in full. Alignment, inline emphasis, links, images and line breaks are honoured; layout tags such as <table> and <ul> only separate paragraphs, and anything else contributes its text but not its appearance.

  • The table of contents starts empty. Word fills it in when the document opens; if it does not, click it and press F9. This is how TOC fields work, not a bug.

Development

npm install
npm run dist          # build the .jpl
npm test              # convert a sample note and write test/output/*.docx
npm run build:webview # rebuild just the mermaid dialog bundle

npm test runs the converter against a stub of the Joplin API, so you can inspect real .docx output without installing anything.

python3 build/make-icons.py regenerates images/ — the icon set and promo tile the plugin store displays. The manifest refers to those files by relative path, and the Joplin plugins website resolves them against repository_url, so they have to stay committed.

Two deliberate deviations from the stock Joplin plugin template are worth knowing about, both commented where they occur:

  • webpack.config.js adds module.noParse for the docx library. It ships a self-contained CommonJS bundle whose internal loader uses a two-argument require() that webpack refuses to parse. The bundle has no external requires, so skipping dependency analysis is safe.
  • build/tsex-stub/ is a local stub package installed as tsex. khroma, a mermaid dependency, publishes a tsconfig.json that extends tsex/tsconfig.json while listing tsex only as a devDependency, so it is never installed and webpack cannot resolve inside khroma. The stub satisfies the reference without pulling in the real toolchain.

The mermaid dialog assets are built by webpack.webview.js rather than the template's extraScripts mechanism, because that mechanism wraps its output as a CommonJS module — correct for Joplin content scripts, but a module is not defined error in a webview.

Licence

MIT