ooxml.dev is an interactive reference for ECMA-376 (Office Open XML) — the standard behind .docx, .xlsx, and .pptx files. Built by the SuperDoc team, who implemented a native OOXML renderer from scratch. Features: live previews (edit XML, see it render in real-time using SuperDoc's native OOXML engine), implementation notes (documents real-world behavior where Microsoft Word diverges from the spec), semantic spec search (18,000+ spec chunks searchable by meaning via MCP server at api.ooxml.dev/mcp), and practical guides for paragraphs, tables, borders, bidirectional text, and document creation. The OOXML spec is 5,000+ pages of PDFs with no rendering guidance — this site bridges that gap with knowledge from people who actually implemented the spec. Covers WordprocessingML (the .docx subset). SuperDoc is open source at superdoc.dev. Built by Caio Pizzol (caiopizzol.com), Head of DX at SuperDoc.
w:pBdr

Paragraph Borders

Borders and shading around paragraphs — side borders, between-border groups, and the space attribute.

Paragraph borders (w:pBdr) draw border lines around paragraphs and can group consecutive paragraphs into a single bordered box. The spec reads straightforward, but Word's rendering rules have several gotchas that aren't documented.

Structure

w:pPr (paragraph properties)
└── w:pBdr (paragraph borders)
    ├── w:top (top border)
    ├── w:bottom (bottom border)
    ├── w:left (left border)
    ├── w:right (right border)
    ├── w:between (between border — separator within groups)
    └── w:bar (vertical bar border)

Each border element has:
├── @w:val     Border style (single, double, dashed, dotted, nil, none...)
├── @w:sz      Width in 1/8 of a point (sz="12" → 1.5pt)
├── @w:space   Distance from text to border, in points
└── @w:color   Hex color (e.g., "000000")

Basic Example

<w:p>
  <w:pPr>
    <w:pBdr>
      <w:top w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:left w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:bottom w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:right w:val="single" w:sz="12" w:space="4" w:color="000000"/>
    </w:pBdr>
  </w:pPr>
  <w:r><w:t>A paragraph with borders on all four sides.</w:t></w:r>
</w:p>

Between Border Groups

When consecutive paragraphs have identical border definitions AND include a w:between element, Word groups them into a single bordered box. The between border draws as a horizontal separator between group members.

<w:p>
  <w:pPr>
    <w:pBdr>
      <w:top w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:left w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:bottom w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:right w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:between w:val="single" w:sz="6" w:space="1" w:color="000000"/>
    </w:pBdr>
  </w:pPr>
  <w:r><w:t>First paragraph in the group.</w:t></w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pBdr>
      <w:top w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:left w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:bottom w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:right w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:between w:val="single" w:sz="6" w:space="1" w:color="000000"/>
    </w:pBdr>
  </w:pPr>
  <w:r><w:t>Second paragraph — between border separates them.</w:t></w:r>
</w:p>

Nil/None Between — Grouping Without a Separator

Setting w:between to val="nil" or val="none" does NOT mean "don't group." It means "group these paragraphs but don't draw a separator." The result is a single continuous bordered box with no divider between paragraphs.

<w:p>
  <w:pPr>
    <w:pBdr>
      <w:top w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:left w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:bottom w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:right w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:between w:val="nil"/>
    </w:pBdr>
  </w:pPr>
  <w:r><w:t>First paragraph — no between separator.</w:t></w:r>
</w:p>
<w:p>
  <w:pPr>
    <w:pBdr>
      <w:top w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:left w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:bottom w:val="single" w:sz="12" w:space="1" w:color="000000"/>
      <w:right w:val="single" w:sz="12" w:space="4" w:color="000000"/>
      <w:between w:val="nil"/>
    </w:pBdr>
  </w:pPr>
  <w:r><w:t>Second paragraph — continuous box, no divider.</w:t></w:r>
</w:p>

How Word Renders Groups

The spec describes w:between but doesn't spell out the rendering rules. Here's what Word actually does with a group of 3 paragraphs:

┌─────────────────────────────┐  ← top border (from A)
│ Paragraph A text            │
├─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┤  ← between border
│ Paragraph B text            │
├─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┤  ← between border
│ Paragraph C text            │
└─────────────────────────────┘  ← bottom border (from C)

- A: top + left + right + between-as-bottom
- B: left + right + between-as-bottom (top suppressed)
- C: left + right + bottom (top suppressed)
- Left/right borders bridge paragraph spacing gaps

Implementation Notes

How between-border grouping works (Word)

Consecutive paragraphs form a group when they all have a w:between element AND all border properties match (top, bottom, left, right, between). Crucially, val="nil" or val="none" still triggers grouping — it means "group without a separator," not "don't group." If you normalize nil/none to undefined during parsing, you lose the grouping signal entirely.

The space attribute and unit mismatch (Word)

The space attribute sets the distance (in points) between a border's inner edge and the text. For between borders, this padding applies on both sides — above and below. Note that sz uses a different unit: eighths of a point (sz="12" = 1.5pt). Easy to mix up since they're on the same element.

Schema

ElementDescription
w:topTop border
w:bottomBottom border
w:leftLeft border
w:rightRight border
w:betweenBorder between grouped paragraphs
w:barVertical bar border (drawn outside the paragraph)
AttributeTypeDescription
w:valST_BorderBorder style — single, double, dashed, dotted, nil, none, etc.
w:szintegerWidth in 1/8 of a point (e.g., 12 = 1.5pt)
w:spaceintegerDistance from text to border inner edge, in points
w:colorhexBorder color (e.g., 000000, auto)
w:shadowbooleanShadow effect on the border
w:framebooleanFrame effect on the border

Spec reference: ECMA-376 §17.3.1.24 (pBdr), §17.3.1.7 (bottom border), §17.3.1.31 (shd)