Skip to content

fix(docx-io): export line breaks the way Word writes them - #5161

Draft
vincent69001 wants to merge 1 commit into
udecode:mainfrom
vincent69001:fix/docx-io-line-breaks
Draft

vincent69001 wants to merge 1 commit into
udecode:mainfrom
vincent69001:fix/docx-io-line-breaks

Conversation

@vincent69001

Copy link
Copy Markdown
Contributor
  • Auto release

🐛 Fixes ➖ N/A
🧭 Task plan: docs/plans/2026-10-12-fix-docx-io-line-breaks.md
🟢 95% confidence in the verified package behavior

Phase 🧪 Tests 🌐 Browser
Reproduced 🔴 On main, <p>first line<br>second line</p> exports <w:br w:type="textWrapping"/> and settings.xml has no w:compat: 2 of the 3 new tests fail ➖ N/A
Verified 🟢 docx-io slow spec (36 pass), docx-io build/typecheck/brl, pnpm check ➖ N/A: no browser surface

✅ Outcome

htmlToDocxBlob, and therefore exportToDocx and DocxExportPlugin, export a <br> the way Word itself writes and renders a Shift+Enter line break:

On main With this PR
<br> in document.xml <w:br w:type="textWrapping"/> <w:br/>
How Word displays it a labelled text wrapping break a plain line break
Justified line ending with the <br> stretched across the whole width left as is, as browsers render it
Page break <w:br w:type="page"/> unchanged

Seen in Word for Mac on a downstream export (a contract with an address, a phone number and an email written line by line in a justified paragraph): each break showed a "[Saut de retour à la ligne]" label (French Word), and every line but the last was spread across the page. Writing the breaks without a type removed the labels; the compat setting removed the stretching.

⚠️ Caveat

w:type already defaults to textWrapping in ECMA-376, so the label is how Word displays an explicitly typed break rather than a spec violation; the fix writes what Word writes for Shift+Enter. w:doNotExpandShiftReturn is a document-wide compatibility setting: a line break a reader later types with Shift+Enter in a justified paragraph is not stretched either, which is the same rule browsers apply. Word for Windows and Word Online were not checked by hand.

🏗️ Design

The change is in the two places that write these parts. buildLineBreak keeps its export and now only writes w:type when a type is passed, so a caller can still ask for page or column; the <br> branch of buildRun calls it without one. The settings template gains <w:compat><w:doNotExpandShiftReturn/></w:compat> between w:defaultTabStop and w:decimalSymbol, where CT_Settings puts it. No option was added: the converter renders HTML, and this setting is what makes Word render a <br> as the HTML does. Today a downstream app has to reopen the generated package and patch both XML parts to get this.

🧪 Verified

  • Reproduced on main with the new tests: the untyped-break and compat tests fail, the page-break test passes.
  • bun test ./packages/docx-io/src/lib/internal/html-to-docx.slow.ts: 36 pass.
  • pnpm turbo build --filter=./packages/docx-io, pnpm turbo typecheck --filter=./packages/docx-io, pnpm turbo brl --filter=./packages/docx-io (no barrel drift), pnpm lint:fix, pnpm check: pass.

AI-assisted (Claude Code), fully tested. Codex is not installed on the contributor's machine, so codex review --base origin/main was not run; an independent Claude review pass was run on the diff instead: no correctness defect, and its accuracy findings (Word for Mac wording, document-wide scope, a test name) are applied.

@codesandbox

codesandbox Bot commented Oct 12, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web Editor • VS Code • Insiders

Open Preview

@changeset-bot

changeset-bot Bot commented Oct 12, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c22e236

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@platejs/docx-io Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

A `<br>` was written as `<w:br w:type="textWrapping"/>`, which Word for Mac displays as a labelled text wrapping
break, and Word stretched the justified line that ends with it while browsers leave that line as is. Write the
plain `<w:br/>` Word writes for Shift+Enter, and declare `w:doNotExpandShiftReturn` in the document settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vincent69001
vincent69001 force-pushed the fix/docx-io-line-breaks branch from 03e6d95 to c22e236 Compare October 12, 2026 15:07

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant