DOCX Format: Inside Microsoft Word's Open XML Standard
DOCX (Word Open XML Document) is Microsoft's document format introduced with Office 2007, replacing the binary DOC format. Unlike its predecessor, DOCX is based on the Office Open XML (OOXML) standard (ISO/IEC 29500), making it a ZIP archive containing XML files, images, fonts, and other resources. Understanding DOCX's internal structure enables programmatic document generation, automated processing, and accurate conversion to other formats.
DOCX Is a ZIP Archive
The first thing to know: a .docx file is a ZIP file. Rename it to .zip and you can open it in any file manager:
document.docx/
├── [Content_Types].xml — declares content types for all parts
├── _rels/
│ └── .rels — root relationships (points to document)
├── word/
│ ├── document.xml — THE main document content (body text)
│ ├── styles.xml — all named styles (Heading 1, Normal, etc.)
│ ├── settings.xml — document-level settings (compatibility, margins)
│ ├── theme/
│ │ └── theme1.xml — color theme, fonts, effects
│ ├── _rels/
│ │ └── document.xml.rels — relationships (images, headers, footers)
│ ├── header1.xml — first page header
│ ├── footer1.xml — first page footer
│ ├── numbering.xml — list numbering definitions
│ ├── footnotes.xml — footnote text
│ ├── endnotes.xml — endnote text
│ ├── comments.xml — review comments
│ ├── fontTable.xml — font information
│ └── media/
│ ├── image1.png — embedded images
│ └── image2.jpg
└── docProps/
├── app.xml — application metadata (word count, pages)
└── core.xml — document properties (title, author, dates)
The document.xml Structure
The main content lives in word/document.xml. The key XML elements:
<w:document>
<w:body>
<!-- Paragraph -->
<w:p>
<w:pPr> <!-- Paragraph Properties -->
<w:pStyle w:val="Heading1"/> <!-- applies Named Style -->
<w:spacing w:before="240" w:after="120"/>
<w:jc w:val="center"/> <!-- alignment: left/center/right/both -->
</w:pPr>
<w:r> <!-- Run (contiguous text with same formatting) -->
<w:rPr> <!-- Run Properties -->
<w:b/> <!-- bold -->
<w:i/> <!-- italic -->
<w:u w:val="single"/> <!-- underline -->
<w:color w:val="FF0000"/> <!-- red text -->
<w:sz w:val="28"/> <!-- font size 14pt (sz in half-points) -->
<w:rFonts w:ascii="Calibri" w:hAnsi="Calibri"/>
</w:rPr>
<w:t>Hello World</w:t>
</w:r>
</w:p>
<!-- Table -->
<w:tbl>
<w:tblPr> <!-- Table Properties -->
<w:tblStyle w:val="TableGrid"/>
<w:tblW w:w="5000" w:type="pct"/> <!-- 100% width -->
</w:tblPr>
<w:tr> <!-- Table Row -->
<w:tc> <!-- Table Cell -->
<w:tcPr>
<w:tcW w:w="2500" w:type="pct"/>
<w:shd w:fill="4472C4" w:val="clear"/> <!-- blue background -->
</w:tcPr>
<w:p><w:r><w:t>Cell content</w:t></w:r></w:p>
</w:tc>
</w:tr>
</w:tbl>
<!-- Section Properties (page size, margins, columns) -->
<w:sectPr>
<w:pgSz w:w="12240" w:h="15840"/> <!-- Letter: 8.5" × 11" in twentieths of a point -->
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/>
</w:sectPr>
</w:body>
</w:document>
Styles System
DOCX uses a powerful cascading styles system in styles.xml:
Style types:
- Paragraph styles: Apply to entire paragraphs (
Heading 1,Normal,Body Text) - Character styles: Apply to inline runs (
Strong,Emphasis,Code) - Table styles: Apply to tables (
Table Grid,Light Shading) - List styles: Apply to numbered/bulleted lists
Style inheritance: each style can have a basedOn parent. Heading 1 is typically based on Normal, inheriting its font but overriding size and weight.
The Normal style is the ultimate base — changing it affects all styles that don't explicitly override each property.
Images in DOCX
Images are stored in word/media/ and referenced via relationships (word/_rels/document.xml.rels). In document.xml, an image reference looks like:
<w:drawing>
<wp:inline distT="0" distB="0" distL="0" distR="0">
<wp:extent cx="5400000" cy="3600000"/> <!-- EMUs: 914400 EMU = 1 inch -->
<a:graphic>
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
<pic:pic>
<pic:blipFill>
<a:blip r:embed="rId5"/> <!-- relationship ID pointing to image file -->
</pic:blipFill>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>
Images use EMU (English Metric Units): 914,400 EMU = 1 inch = 72 points = 96 CSS pixels at 96 DPI.
Track Changes
DOCX's Track Changes feature stores every edit as markup:
<w:ins w:id="1" w:author="John Smith" w:date="2024-01-15T10:30:00Z">
<w:r><w:t>inserted text</w:t></w:r>
</w:ins>
<w:del w:id="2" w:author="Jane Doe" w:date="2024-01-15T11:00:00Z">
<w:r><w:delText>deleted text</w:delText></w:r>
</w:del>
Accepting all changes removes the markup and keeps only the final content; rejecting all changes removes insertions and restores deletions.
Programmatic DOCX Generation
Python — python-docx
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
doc = Document()
# Add heading
doc.add_heading('Document Title', level=1)
# Add paragraph with formatting
para = doc.add_paragraph()
run = para.add_run('Bold text ')
run.bold = True
run = para.add_run('and normal text.')
para.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY
# Add table
table = doc.add_table(rows=3, cols=3)
table.style = 'Table Grid'
for i, row in enumerate(table.rows):
for j, cell in enumerate(row.cells):
cell.text = f'Row {i}, Col {j}'
# Add image
doc.add_picture('logo.png', width=Inches(2))
# Set page margins
section = doc.sections[0]
section.top_margin = Inches(1)
section.bottom_margin = Inches(1)
doc.save('output.docx')
PHP — PhpWord
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection();
// Add formatted text
$section->addText(
'Hello World',
['bold' => true, 'size' => 16, 'color' => '333333'],
['alignment' => \PhpOffice\PhpWord\SimpleType\Jc::CENTER]
);
// Add table
$table = $section->addTable(['borderSize' => 6, 'borderColor' => 'CCCCCC']);
$table->addRow();
$table->addCell(2000)->addText('Name');
$table->addCell(3000)->addText('Value');
$phpWord->save('output.docx', 'Word2007');
LibreOffice Headless (conversion)
# Convert DOCX to PDF
libreoffice --headless --convert-to pdf document.docx
# Convert DOCX to HTML
libreoffice --headless --convert-to html document.docx
# Batch convert all DOCX in directory
libreoffice --headless --convert-to pdf --outdir ./output/ *.docx
DOCX vs. ODT vs. PDF vs. RTF
| Format | Editability | Fidelity | Size | Open Spec |
|---|---|---|---|---|
| DOCX | Full | MS Office-native | Medium | Yes (OOXML) |
| ODT | Full | Best in LibreOffice | Smaller | Yes (ODF) |
| Read-only* | Pixel-perfect | Varies | Yes (PDF/A) | |
| RTF | Limited | Good | Large | Yes |
| HTML | Limited | Good | Small | Yes |
*PDF/A and tagged PDF can be edited with Acrobat Pro.
Common Issues and Solutions
Issue: DOCX opens with different fonts on different computers Cause: Fonts are referenced by name but not embedded Fix: Embed fonts in Word (File → Options → Save → Embed fonts in file) or convert to PDF
Issue: Track changes visible in PDF export
Cause: Changes were not accepted/rejected before export
Fix: Review → Accept All Changes before saving/exporting
Issue: Images shift position when text is added Cause: Images set to "In Line with Text" but page dimensions change Fix: Set image to "Fixed Position on Page" (Layout Options → Fix position on page)
Issue: DOCX file is very large despite little content Cause: Deleted content remains in the Undo history stored in the file Fix: Copy content to new document, or use File → Options → Advanced → Preserve fidelity → uncheck "Embed linguistic data"
Summary
DOCX's ZIP+XML architecture makes it the most programmable major document format. Its structure is well-documented under ECMA-376 and ISO/IEC 29500, enabling generation by dozens of libraries across every programming language. For document exchange, DOCX is the universal standard. For archival or print, convert to PDF/A. For open-source toolchain compatibility, consider ODT. But for maximum compatibility with the world's most installed office suite, DOCX remains the definitive document format.
Related conversions
Document conversions that follow this topic naturally: