How to Configure Tables with Dual Widths for DOCX Cross-Platform Compatibility
To ensure tables render consistently across Microsoft Word, Google Docs, and LibreOffice, you must define both table-level columnWidths and cell-level width properties using DXA units, ensuring the values sum exactly to the total table width.
When generating Word documents programmatically using the docx JavaScript library within the anthropics/skills repository, tables require a specific dual-width configuration pattern. According to the specification in skills/docx/SKILL.md, omitting either the table-level or cell-level width definitions causes rendering inconsistencies across different word processors.
Why Dual Widths Are Required for Cross-Platform DOCX Tables
Word processing applications interpret table dimensions differently when width specifications are incomplete. Microsoft Word might auto-adjust column widths based on content, while Google Docs collapses tables entirely when percentages are used, and LibreOffice applies inconsistent spacing.
The critical excerpt from the skill definition states:
CRITICAL: Tables need dual widths – set both
columnWidthson the table ANDwidthon each cell. Without both, tables render incorrectly on some platforms. — SKILL.md line 175-186
The Three-Layer Width Configuration
To achieve cross-platform compatibility, you must configure widths at three distinct levels, all using DXA units (twentieths of a point, where 1 inch = 1440 DXA).
1. Table-Level Width
Define the total table width using WidthType.DXA. For a standard US Letter page with 1-inch margins, the content width is 9360 DXA (12240 DXA page width minus 2880 DXA for both margins).
const tableWidth = 9360;
const table = new Table({
width: { size: tableWidth, type: WidthType.DXA },
// ... additional configuration
});
2. Column Widths Array
Provide a columnWidths array where the sum of all values exactly equals the table-level width. This array defines the relative sizing of each column.
const columnWidths = [4680, 4680]; // Sum equals 9360
const table = new Table({
width: { size: tableWidth, type: WidthType.DXA },
columnWidths: columnWidths,
// ... rows configuration
});
3. Cell-Level Width
Each TableCell must explicitly set its own width property to match the corresponding value from the columnWidths array. This redundancy ensures that all platforms interpret the cell dimensions identically.
new TableCell({
width: { size: columnWidths[0], type: WidthType.DXA },
// ... other cell properties
})
Complete Implementation Example
The following example demonstrates a complete, runnable implementation that creates a two-column table with consistent dual-width configuration:
const {
Document, Packer, Paragraph, Table, TableRow, TableCell,
WidthType, BorderStyle, ShadingType,
} = require('docx');
const fs = require('fs');
// Define consistent border styling
const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" };
const borders = { top: border, bottom: border, left: border, right: border };
// US Letter with 1-inch margins: 12240 - (2 * 1440) = 9360 DXA
const tableWidth = 9360;
const columnWidths = [4680, 4680]; // Must sum to tableWidth
const table = new Table({
width: { size: tableWidth, type: WidthType.DXA },
columnWidths: columnWidths,
rows: [
new TableRow({
children: [
new TableCell({
borders,
width: { size: columnWidths[0], type: WidthType.DXA },
shading: { fill: "D5E8F0", type: ShadingType.CLEAR },
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph("Column A")]
}),
new TableCell({
borders,
width: { size: columnWidths[1], type: WidthType.DXA },
shading: { fill: "D5E8F0", type: ShadingType.CLEAR },
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph("Column B")]
})
]
})
]
});
const doc = new Document({
sections: [{ children: [table] }]
});
Packer.toBuffer(doc).then(buffer => {
fs.writeFileSync('dual-width-table.docx', buffer);
console.log('Document created successfully with dual-width configuration');
});
Common Pitfalls and Platform-Specific Behavior
According to the width rules documented in skills/docx/SKILL.md (lines 13-18), several specific constraints prevent cross-platform compatibility issues:
-
Avoid Percentage Widths: While the
docxlibrary supportsWidthType.PERCENTAGE, Google Docs ignores percentage-based table widths, causing tables to collapse to minimum content width. Always useWidthType.DXA. -
Exact Summation: The sum of the
columnWidthsarray must precisely equal the table-level width. Even a 1 DXA discrepancy can cause rounding errors in LibreOffice. -
Cell Margins Are Internal: When calculating widths, remember that cell margins (padding) are internal spacing and do not add to the cell width calculation. The
widthproperty defines the total cell width including margins.
Summary
- Dual-width configuration requires three synchronized values: table-level
width,columnWidthsarray, and individual cellwidthproperties. - Use DXA units exclusively (1 inch = 1440 DXA) rather than percentages to ensure compatibility with Google Docs and LibreOffice.
- Column widths must sum exactly to the table width, and each cell must reference the corresponding column width value.
- Cell margins are internal padding and do not affect the width calculation, but must be accounted for in content layout.
- Reference implementation is documented in
skills/docx/SKILL.mdwithin the anthropics/skills repository.
Frequently Asked Questions
What happens if I only set table-level width without cell-level widths?
If you omit the width property on individual TableCell instances, Microsoft Word may auto-adjust column widths based on content, while Google Docs and LibreOffice often render columns with inconsistent spacing or collapsed widths. According to the skills/docx/SKILL.md specification, both values are required for deterministic cross-platform rendering.
Why does Google Docs break with percentage-based table widths?
Google Docs does not properly interpret WidthType.PERCENTAGE values when importing DOCX files, causing tables to collapse to their minimum content width regardless of the specified percentage. The skills/docx/SKILL.md documentation explicitly recommends using WidthType.DXA (twentieths of a point) for all width specifications to ensure consistent rendering across Microsoft Word, Google Docs, and LibreOffice.
How do I calculate DXA units for custom page sizes?
One inch equals 1440 DXA units. For standard US Letter (8.5 × 11 inches) with 1-inch margins, calculate the content width as follows: page width (12240 DXA) minus left margin (1440 DXA) minus right margin (1440 DXA) equals 9360 DXA. For A4 or custom sizes, multiply the page width in inches by 1440, then subtract the margin DXA values accordingly.
Can I use auto-fit or percentage widths for cross-platform compatibility?
No, WidthType.AUTO and WidthType.PERCENTAGE should be avoided for cross-platform compatibility. Auto-fit widths produce inconsistent column sizing between Microsoft Word and LibreOffice, while percentages cause rendering failures in Google Docs. The skills/docx/SKILL.md specification mandates using explicit DXA values at both the table and cell levels to guarantee consistent layout across all major word processing platforms.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →