Repository navigation
DOCX Writing
MarkdownToDocx writes GitHub/Obsidian/DocC alerts (> [!NOTE], > [!WARNING] Watch out,
any [!KIND], > Note:) as boxes of ordinary paragraphs: a tinted fill with the kind's
coloured left border, laid out like the CSS box of the HTML/PDF output. Detection
(MarkdownAlertBlock), colours (MarkdownAlertPalette) and geometry (MarkdownAlertLayout,
in CSS em) are shared with every other writer, so the boxes look alike in all formats.
A stylesheet can recolour them: MarkdownAlertColors(css:) reads its .markdown-alert and
.markdown-alert-KIND rules (fill, left border, text colour), and swifttext render --css applies
them to DOCX and Pages as it does to HTML, PDF and EPUB.
DocxFile.markdown() (and swifttext docx --markdown) reads them back as > [!KIND] Title.
| Option | Breaks across pages | Plain, editable, extractable text | Reads back |
|---|---|---|---|
| Paragraph borders + shading (used) | yes; Word closes and reopens the box at the break | yes | by style |
| DrawingML text box | no | no: a floating object that screen readers and extractors skip or double | poorly |
| Single-cell table | Word yes, Pages never (rows don't split) | as a table (the accessibility checker flags it) | by table style |
Microsoft's own help recommends paragraph borders over text boxes and one-cell tables for setting text off.
Each kind used in the document gets a pair of paragraph styles:
| Style id | Name | Carries |
|---|---|---|
SwiftTextCallout-<kind> |
Callout Note | the frame (w:pBdr), fill (w:shd), indents, text colour, keepLines
|
SwiftTextCalloutTitle-<kind> |
Callout Note Title |
basedOn the body style: bold, keepNext
|
The title inherits the frame, so title and body draw as one box. The reader recognises the
styles by id, or by name when another app rewrote the ids (LibreOffice builds ids from the
names). A rule is an empty paragraph in Horizontal Rule (SwiftTextRule): a bottom border
under an exact 1pt line. It reads back as ---.
- Consecutive paragraphs with identical borders and identical left/right indents form one box (ECMA-376 §17.3.1.24). The space between them is inside the box and shaded. First-line and hanging indents don't count.
- A border's
w:spaceis the padding between text and border, in whole points (at most 31), and the shading fills it. Word pads only towards a side that has a border, so the top, bottom and right sides get ½pt borders in the fill colour. - Side borders sit outside the indents. Indent = padding + border width puts the box's outer edge on the text column.
- The first paragraph's space before and the last one's space after are outside the box: they are its margins.
- Word adds one paragraph's space after to the next one's space before; CSS collapses adjacent margins to the larger.
All values are the CSS em values times the body font size (DocxWriter.bodyFontSize, 11pt),
in twips:
- Margin 0.8em above and below, net of the neighbour's own spacing. A title after a Normal paragraph (6pt after) gets 0.8em − 6pt before. The last paragraph before a heading gets 0.8em − the heading's space before, but at least 0. A box or rule next to another box or rule takes its full margin, and the other one takes none.
- The line after a box or rule gets CSS's half-leading (0.3em) as extra margin, because Word puts a line's extra leading below the text and CSS splits it above and below.
-
Padding 0.75em above and below (the top and bottom borders'
w:space), 1em at the sides. - Between paragraphs 0.6em, and 0.2em between list items.
-
keepNexton every paragraph but the last (CSSbreak-inside: avoid).
Two boxes in a row would join into one, even of different kinds when their palettes match. An unbordered 1pt spacer paragraph therefore parts them; the reader skips it.
-
Lists: a list item's indent would split the box, so every paragraph of a box that holds
a list shares one wider indent (left
w:space1em + the 18pt bullet hang) and the bullets hang in the padding. Nested items keep theirw:ilvl(and glyph) but share that indent. -
Headings become bold lines, quotes italic ones, and code blocks one monospace
paragraph with
w:brline breaks (a code table would split the box). They read back as emphasis and plain lines. The Pages writer does the same. - Tables, images and rules can't sit inside a paragraph box. They split it: the box closes before them and continues after them, without a title.
Quoted paragraphs use the Block Quote style (SwiftTextBlockQuote: a grey left bar at
one level's indent). Deeper levels add 360 twips of direct indent each, and the reader turns
the indent back into > > . It also takes Word's own Quote and Intense Quote styles
as quotes. Two quotes in a row would join under one bar, so the same unstyled spacer that
parts two boxes parts them, and the reader takes it as the boundary.
Code blocks stay single-cell tables of Code Block paragraphs. The reader turns each cell back into one fenced block. It keeps the empty paragraphs (blank lines) and the indentation, and uses a longer fence when the code holds backticks.
Without Word, this layout follows the specification and Word's documented behaviour. It was
checked only for well-formed XML and by reading the files back. Points to confirm in Word:
the shading between the grouped paragraphs (expected continuous), and where Word puts the
leading of auto line spacing (it decides how much of the half-leading compensation is
right).
Generated from Docs/DOCX_WRITING.md in the repo; edit via a merge request.