How DXA Units and Table Widths Are Calculated in docx-js
docx-js uses DXA (twentieths of a point) as its base unit for all dimensional values, where 1 inch equals 1440 DXA, and requires table widths to exactly match the sum of their column widths.
The anthropics/skills repository provides definitive guidance on dimensional calculations in docx-js, specifying how page sizes, margins, and table layouts must be expressed in DXA units to generate valid Word documents.
Understanding DXA Units in docx-js
DXA (twentieths of a point) is the fundamental unit of measurement in docx-js. All dimensional values—including page sizes, margins, and table widths—must be provided as integers representing twentieths of a point.
The conversion is straightforward: 1 inch = 1440 DXA. This means an 8.5-inch width equals 12,240 DXA, and an 11-inch height equals 15,840 DXA.
According to the source documentation in skills/docx/SKILL.md, docx-js defaults to A4 dimensions (11,906 × 16,838 DXA) when page sizes are not explicitly specified.
Calculating Page and Content Width
When creating documents with specific page layouts, you must calculate the available content width by subtracting margins from the total page width.
For a standard U.S. Letter page (8.5 × 11 inches) with 1-inch margins on all sides:
import { Document } from "docx";
const pageWidth = 12240; // 8.5 inches in DXA
const leftMargin = 1440; // 1 inch in DXA
const rightMargin = 1440; // 1 inch in DXA
const contentWidth = pageWidth - leftMargin - rightMargin; // 9360 DXA
const doc = new Document({
sections: [
{
properties: {
page: {
size: {
width: 12240,
height: 15840, // 11 inches in DXA
},
margin: {
top: 1440,
right: 1440,
bottom: 1440,
left: 1440,
},
},
},
children: [/* content */],
},
],
});
Table Width Calculation Rules
Tables in docx-js require strict adherence to the dual-width rule: the table's total width must exactly equal the sum of its columnWidths, and each cell must explicitly declare a width matching its corresponding column.
As documented in skills/docx/SKILL.md, using WidthType.PERCENTAGE or omitting width values causes rendering failures, particularly in Google Docs.
import { Table, TableRow, TableCell, Paragraph, WidthType } from "docx";
const columnWidth1 = 4680; // 3.25 inches
const columnWidth2 = 4680; // 3.25 inches
const totalTableWidth = columnWidth1 + columnWidth2; // 9360 DXA
const table = new Table({
width: {
size: totalTableWidth,
type: WidthType.DXA,
},
columnWidths: [columnWidth1, columnWidth2],
rows: [
new TableRow({
children: [
new TableCell({
width: {
size: columnWidth1,
type: WidthType.DXA,
},
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph("First Column")],
}),
new TableCell({
width: {
size: columnWidth2,
type: WidthType.DXA,
},
margins: { top: 80, bottom: 80, left: 120, right: 120 },
children: [new Paragraph("Second Column")],
}),
],
}),
],
});
Handling Landscape Orientation
When configuring landscape orientation, docx-js internally swaps the width and height values. You must still provide the dimensions as if the page were in portrait orientation (short edge as width, long edge as height), and set orientation: PageOrientation.LANDSCAPE.
As shown in skills/docx/SKILL.md, the library handles the rotation automatically:
import { Document, PageOrientation } from "docx";
const doc = new Document({
sections: [
{
properties: {
page: {
size: {
width: 12240, // 8.5 in (short edge)
height: 15840, // 11 in (long edge)
orientation: PageOrientation.LANDSCAPE,
},
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 },
},
},
children: [/* content */],
},
],
});
Validating DXA Calculations
The anthropics/skills repository includes validation tools to ensure your DXA calculations produce valid Word documents. The DOCXSchemaValidator in skills/docx/scripts/office/validate.py enforces schema compliance, while skills/docx/scripts/office/validators/docx.py specifically checks for malformed tables and missing width attributes.
Running these validators helps catch common errors such as mismatched table and column widths before the document reaches end users.
Summary
- DXA units are the foundation of dimensional calculations in
docx-js, with 1 inch = 1440 DXA. - Page dimensions must be explicitly set in DXA; otherwise, the library defaults to A4 (11,906 × 16,838 DXA).
- Content width equals page width minus left and right margins, all expressed in DXA.
- Table widths must exactly match the sum of
columnWidths, and every cell requires an explicitwidthproperty usingWidthType.DXA. - Landscape orientation requires passing portrait dimensions (width < height) and setting
PageOrientation.LANDSCAPE.
Frequently Asked Questions
How do I convert inches to DXA units for docx-js?
Multiply the inch value by 1440. For example, 8.5 inches equals 12,240 DXA (8.5 × 1440), and 1 inch equals 1,440 DXA. Always use integer values when configuring page sizes, margins, or table widths in docx-js.
Why does my table render incorrectly in Google Docs?
Google Docs strictly enforces the DXA width rules that docx-js expects. If your table uses WidthType.PERCENTAGE, omits the width property on cells, or has a table width that does not equal the sum of columnWidths, Google Docs will display the table with incorrect or inconsistent column widths. Always use WidthType.DXA and ensure exact mathematical equality between table width and column width sums.
Do I need to swap width and height for landscape orientation?
No. When using PageOrientation.LANDSCAPE, provide the dimensions as if the page were in portrait orientation (short edge as width, long edge as height). The docx-js library internally swaps these values when generating the Word XML. For U.S. Letter landscape, use width: 12240 (8.5 in) and height: 15840 (11 in) alongside the landscape orientation flag.
How do I calculate the available content width for tables?
Subtract the left and right margins from the total page width, ensuring all values are in DXA. For a U.S. Letter page (12,240 DXA wide) with 1-inch margins (1,440 DXA each side), the calculation is: 12,240 − 1,440 − 1,440 = 9,360 DXA. This value should be used as your table's total width, which then must be divided among your columnWidths array.
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 →