Tables
Paragraphs requires an understanding of Sections.
Intro
Tablescontain a list ofRowsRowscontain a list ofTableCellsTableCellscontain a list ofParagraphsand/orTables. You can addTablesas tables can be nested inside each other
Create a simple table like so:
const table = new Table({
rows: [Array of `TableRow`s]
});Then add the table in the section
const doc = new Document({
sections: [
{
children: [table],
},
],
});Table
Options
Here is a list of options you can add to the table:
| Property | Type | Notes |
|---|---|---|
| rows | Array<TableRow> | Required |
| width | ITableWidthProperties | Optional. Defaults to { size: 100 } (auto) |
| columnWidths | Array<number> | Optional. Width of each grid column in twips |
| margins | ITableCellMarginOptions | Optional. Default cell margins for the whole table |
| indent | ITableWidthProperties | Optional |
| float | ITableFloatOptions | Optional. See Floating tables |
| layout | TableLayoutType | Optional. AUTOFIT or FIXED |
| style | string | Optional. Id of a table style defined in the document |
| borders | ITableBordersOptions | false | Optional. See Table borders |
| alignment | AlignmentType | Optional. Aligns the whole table on the page |
| visuallyRightToLeft | boolean | Optional |
| tableStyleOptions | ITableStyleOptions | Optional. See Table Style Options |
| cellSpacing | ITableCellSpacingProperties | Optional. Spacing between cells |
| shading | IShadingAttributesProperties | Optional. Background shading for the whole table |
Set Width
const table = new Table({
...,
width: {
size: [TABLE_WIDTH],
type: WidthType,
}
});For example:
const table = new Table({
...,
width: {
size: 4535,
type: WidthType.DXA,
}
});Depending on the WidthType, size accepts different values:
- a plain
number(twips forWidthType.DXA, converted to"<number>%"forWidthType.PERCENTAGE) - a percent string such as
"50%" - a universal measure string such as
"1.5in","25mm"or"12pt"
const table = new Table({
...,
width: {
size: "50%",
type: WidthType.PERCENTAGE,
}
});Column Widths
columnWidths sets the width of each grid column in twips (twentieths of a point). Provide one entry per column. This is especially useful together with TableLayoutType.FIXED:
const table = new Table({
...,
columnWidths: [3000, 3000, 3000], // three columns, 3000 twips each
layout: TableLayoutType.FIXED,
});If omitted, a default grid is generated with one column per grid column found in the rows.
Layout
layout selects the algorithm Word uses to lay out the table:
TableLayoutType.AUTOFIT— columns expand to fit their contentTableLayoutType.FIXED— columns keep the widths from the table grid
const table = new Table({
...,
layout: TableLayoutType.FIXED,
});Alignment
Aligns the whole table on the page using the same AlignmentType used for paragraphs:
const table = new Table({
...,
alignment: AlignmentType.CENTER,
});Table-wide Cell Margins
margins sets the default cell margins for every cell in the table. Values are in the unit given by marginUnitType (defaults to WidthType.DXA, i.e. twips):
const table = new Table({
...,
margins: {
marginUnitType: WidthType.DXA,
top: 100,
bottom: 100,
left: 150,
right: 150,
},
});Individual cells can override these with their own margins option.
Cell Spacing
cellSpacing adds spacing between the cells of the table:
const table = new Table({
...,
cellSpacing: {
value: 100,
type: CellSpacingType.DXA, // the default; CellSpacingType.NIL removes spacing
},
});Cell spacing can also be set per row — see the table row options.
Style
style references a table style by its id. This is useful when working with an existing template (e.g. via externalStyles) that defines table styles such as Word's built-in "TableGrid":
const table = new Table({
...,
style: "TableGrid",
});Table Borders
Table-level borders are set with the borders option. In addition to the four outer sides, tables support insideHorizontal and insideVertical for the lines between cells:
const table = new Table({
...,
borders: {
top: { style: BorderStyle.DOUBLE, size: 6, color: "ff0000" },
bottom: { style: BorderStyle.DOUBLE, size: 6, color: "ff0000" },
left: { style: BorderStyle.SINGLE, size: 4, color: "auto" },
right: { style: BorderStyle.SINGLE, size: 4, color: "auto" },
insideHorizontal: { style: BorderStyle.DASHED, size: 2, color: "999999" },
insideVertical: { style: BorderStyle.DASHED, size: 2, color: "999999" },
},
});Note: Any side you leave out (including when borders is omitted entirely) falls back to a default single border (BorderStyle.SINGLE, size 4, color "auto"). To create a borderless table, use the TableBorders.NONE preset, which sets all six sides to BorderStyle.NONE:
const table = new Table({
...,
borders: TableBorders.NONE,
});Inheriting borders from a table style
Direct borders take precedence over the table style referenced by style — and that includes BorderStyle.NONE, which is still a direct border, just an invisible one. So neither omitting sides nor TableBorders.NONE will let a style's own borders show through.
To emit no tblBorders at all and let the style own the borders, pass borders: false:
const table = new Table({
...,
style: "TableGrid",
borders: false,
});borders: false and TableBorders.NONE are not the same thing. TableBorders.NONE writes six
explicit none borders, which override the style and give you a borderless table. borders: false writes nothing, letting whatever the style defines apply.
Floating Tables
By default a table is placed inline with the surrounding text. The float option turns it into a floating table that is positioned freely on the page, with text flowing around it.
const table = new Table({
rows: [...],
float: {
horizontalAnchor: TableAnchorType.MARGIN,
verticalAnchor: TableAnchorType.MARGIN,
relativeHorizontalPosition: RelativeHorizontalPosition.RIGHT,
relativeVerticalPosition: RelativeVerticalPosition.BOTTOM,
overlap: OverlapType.NEVER,
leftFromText: 1000,
rightFromText: 2000,
topFromText: 1500,
bottomFromText: 30,
},
width: {
size: 4535,
type: WidthType.DXA,
},
layout: TableLayoutType.FIXED,
});Float Options
| Property | Type | Notes |
|---|---|---|
| horizontalAnchor | TableAnchorType | Optional. Base object for horizontal positioning: MARGIN, PAGE or TEXT. Assumed page if omitted |
| verticalAnchor | TableAnchorType | Optional. Base object for vertical positioning: MARGIN, PAGE or TEXT. Assumed page if omitted |
| absoluteHorizontalPosition | number | UniversalMeasure | Optional. Absolute horizontal offset from the anchor, in twips (may be negative) or a measure like "1in" |
| relativeHorizontalPosition | RelativeHorizontalPosition | Optional. CENTER, INSIDE, LEFT, OUTSIDE or RIGHT. Supersedes absoluteHorizontalPosition |
| absoluteVerticalPosition | number | UniversalMeasure | Optional. Absolute vertical offset from the anchor, in twips (may be negative) or a measure like "1in" |
| relativeVerticalPosition | RelativeVerticalPosition | Optional. CENTER, INSIDE, BOTTOM, OUTSIDE, INLINE or TOP. Supersedes absoluteVerticalPosition |
| topFromText | number | PositiveUniversalMeasure | Optional. Minimum distance between the table and the text above it, in twips |
| bottomFromText | number | PositiveUniversalMeasure | Optional. Minimum distance between the table and the text below it, in twips |
| leftFromText | number | PositiveUniversalMeasure | Optional. Minimum distance between the table and the text to its left, in twips |
| rightFromText | number | PositiveUniversalMeasure | Optional. Minimum distance between the table and the text to its right, in twips |
| overlap | OverlapType | Optional. NEVER or OVERLAP — whether other floating tables may overlap this one |
Set Indent
const table = new Table({
...,
indent: {
size: 600,
type: WidthType.DXA,
}
});Table Row
A table consists of multiple table rows. Table rows have a list of children which accepts a list of table cells explained below. You can create a simple table row like so:
const tableRow = new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
});Or preferably, add the tableRow directly into the table without declaring a variable:
const table = new Table({
rows: [
new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
}),
],
});Options
Here is a list of options you can add to the table row:
| Property | Type | Notes |
|---|---|---|
| children | Array<TableCell> | Required |
| cantSplit | boolean | Optional |
| tableHeader | boolean | Optional |
| height | { value: number | PositiveUniversalMeasure, rule: HeightRule } | Optional |
| cellSpacing | ITableCellSpacingProperties | Optional. Cell spacing for this row only |
height.value accepts a number in twips or a universal measure string:
const row = new TableRow({
...,
height: {
value: "0.5in",
rule: HeightRule.EXACT,
},
});A row can also override the table-wide cell spacing:
const row = new TableRow({
...,
cellSpacing: {
value: 50,
type: CellSpacingType.DXA,
},
});Repeat row
If a table is paginated on multiple pages, it is possible to repeat a row at the top of each new page by setting tableHeader to true:
const row = new TableRow({
...,
tableHeader: true,
});Pagination
Prevent row pagination
To prevent breaking contents of a row across multiple pages, call cantSplit:
const row = new Row({
...,
cantSplit: true,
});Table Cells
Cells need to be added in the table row, you can create a table cell like:
const tableCell = new TableCell({
children: [new Paragraph("hello")],
});Or preferably, add the tableRow directly into the table row without declaring a variable:
const tableRow = new TableRow({
children: [
new TableCell({
children: [new Paragraph("hello")],
}),
],
});Note: A cell must end with a paragraph. If the last child of a cell is not a Paragraph (for example a nested Table, or an empty children array), an empty paragraph is appended to the cell automatically when the document is generated.
Options
| Property | Type | Notes |
|---|---|---|
| children | Array<Paragraph or Table> | Required. You can nest tables by adding a table into a cell |
| shading | IShadingAttributesProperties | Optional |
| margins | ITableCellMarginOptions | Optional |
| verticalAlign | VerticalAlignTable | Optional |
| textDirection | TextDirection | Optional. Rotates the text inside the cell |
| verticalMerge | VerticalMergeType | Optional. Low-level vertical merge; prefer rowSpan |
| columnSpan | number | Optional |
| rowSpan | number | Optional |
| borders | ITableCellBorders | Optional |
| width | ITableWidthProperties | Optional |
Border Options
| Property | Type | Notes |
|---|---|---|
| top | { style: BorderStyle, size: number, color: string } | Optional |
| bottom | { style: BorderStyle, size: number, color: string } | Optional |
| left | { style: BorderStyle, size: number, color: string } | Optional |
| right | { style: BorderStyle, size: number, color: string } | Optional |
| start | { style: BorderStyle, size: number, color: string } | Optional. Logical start edge (text-direction aware) |
| end | { style: BorderStyle, size: number, color: string } | Optional. Logical end edge (text-direction aware) |
Example
const cell = new TableCell({
...,
borders: {
top: {
style: BorderStyle.DASH_DOT_STROKED,
size: 1,
color: "ff0000",
},
bottom: {
style: BorderStyle.THICK_THIN_MEDIUM_GAP,
size: 5,
color: "889900",
},
},
});Google DOCS
Google DOCS does not support start and end borders, instead they use left and right borders. So to set left and right borders for Google DOCS you should use:
const cell = new TableCell({
...,
borders: {
left: {
style: BorderStyle.DOT_DOT_DASH,
size: 3,
color: "00FF00",
},
right: {
style: BorderStyle.DOT_DOT_DASH,
size: 3,
color: "ff8000",
},
},
});Add paragraph to a cell
Once you have got the cell, you can add data to it:
const cell = new TableCell({
children: [new Paragraph("Hello")],
});Set width of a cell
You can specify the width of a cell using:
const cell = new TableCell({
...,
width: {
size: number,
type: WidthType,
},
});WidthType values can be:
| Property | Notes |
|---|---|
| AUTO | |
| DXA | Value is in twentieths of a point |
| NIL | Is considered as zero |
| PERCENTAGE | Percent of table width |
As with the table width, size accepts a plain number, a percent string ("25%") or a universal measure string ("1.5in"), depending on the WidthType.
Cell Margins
A cell can override the table-wide cell margins. Values are in the unit given by marginUnitType (defaults to WidthType.DXA, i.e. twips):
const cell = new TableCell({
...,
margins: {
marginUnitType: WidthType.DXA,
top: 200,
bottom: 200,
left: 200,
right: 200,
},
});Text Direction
textDirection rotates the text inside a cell, e.g. for vertical header cells:
const cell = new TableCell({
...,
textDirection: TextDirection.BOTTOM_TO_TOP_LEFT_TO_RIGHT,
});TextDirection values can be:
| Property | Notes |
|---|---|
| LEFT_TO_RIGHT_TOP_TO_BOTTOM | Normal horizontal text. The default |
| BOTTOM_TO_TOP_LEFT_TO_RIGHT | Text rotated 90° counter-clockwise |
| TOP_TO_BOTTOM_RIGHT_TO_LEFT | Text rotated 90° clockwise |
Nested Tables
To have a table within a table, simply add it in the children block of a table cell:
const cell = new TableCell({
children: [new Table(...)],
});Vertical Align
Sets the vertical alignment of the contents of the cell
const cell = new TableCell({
...,
verticalAlign: VerticalAlignTable,
});VerticalAlignTable values can be:
| Property | Notes |
|---|---|
| BOTTOM | Align the contents on the bottom |
| CENTER | Align the contents on the center |
| TOP | Align the contents on the top. The default |
For example, to center align a cell:
const cell = new TableCell({
verticalAlign: VerticalAlignTable.CENTER,
});Note: The old VerticalAlign export is deprecated. Use VerticalAlignTable for table cells (VerticalAlign aliases VerticalAlignSection, which additionally contains BOTH — a value that is only valid for section properties, not table cells).
Merging cells together
Row Merge
When cell rows are merged, it counts as multiple rows, so be sure to remove excess cells. It is similar to how HTML's rowspan works.
https://www.w3schools.com/tags/att_td_rowspan.asp
const cell = new TableCell({
...,
rowSpan: [NUMBER_OF_CELLS_TO_MERGE],
});Example
The example will merge three rows together.
const cell = new TableCell({
...,
rowSpan: 3,
});Manual vertical merge
rowSpan is a convenience: internally, the first cell is marked with VerticalMergeType.RESTART and continuation cells are inserted into the following rows with VerticalMergeType.CONTINUE for you. If you need full control (for example when constructing every row yourself), you can set verticalMerge directly instead:
// First row: the cell that starts the merge
new TableCell({
children: [new Paragraph("merged")],
verticalMerge: VerticalMergeType.RESTART,
});
// Following rows: cells that continue the merge
new TableCell({
children: [],
verticalMerge: VerticalMergeType.CONTINUE,
});If both are set, verticalMerge takes precedence over rowSpan for the cell's own merge marker, so avoid mixing the two on the same cell.
Column Merge
When cell columns are merged, it counts as multiple columns, so be sure to remove excess cells. It is similar to how HTML's colspan works.
https://www.w3schools.com/tags/att_td_colspan.asp
const cell = new TableCell({
...,
columnSpan: [NUMBER_OF_CELLS_TO_MERGE],
});Example
The example will merge three columns together.
const cell = new TableCell({
...,
columnSpan: 3,
});Visual Right to Left Table
It is possible to reverse how the cells of the table are displayed. The table direction. More info here: https://superuser.com/questions/996912/how-to-change-a-table-direction-in-microsoft-word
const table = new Table({
visuallyRightToLeft: true,
});Table Style Options (Conditional Formatting)
Table styles can define special formatting for the header row, the first column, banded rows, and so on. tableStyleOptions decides which of those the table actually uses. These are the same six checkboxes Word shows in the Table Style Options group of the Table Design tab, and each one is true when the box is checked:
const table = new Table({
style: "GridTable5Dark-Accent3",
tableStyleOptions: {
headerRow: true, // Header Row: checked
totalRow: true, // Total Row: checked
bandedRows: false, // Banded Rows: unchecked
},
});Because tableStyleOptions only selects parts of a table style, it has no visible effect on a table without a style.
Mapping to Word's checkboxes
| Word checkbox | Property | Default |
|---|---|---|
| Header Row | headerRow | true |
| Total Row | totalRow | false |
| Banded Rows | bandedRows | true |
| First Column | firstColumn | true |
| Last Column | lastColumn | false |
| Banded Columns | bandedColumns | false |
The underlying w:tblLook element stores banding as the negative attributes noHBand and
noVBand. bandedRows and bandedColumns follow Word's checkboxes instead and are inverted on
the way out, so you never have to write a double negative.
Header Row is not "Repeat Header Rows"
headerRow decides whether the style paints its header band. It is not the same as Word's Repeat Header Rows (on the Layout tab), which repeats a row across page breaks — that is tableHeader on TableRow. Word keeps the two apart and so does this library: setting one never implies the other.
Defaults
The defaults above match Word's own: Header Row, First Column and Banded Rows checked; Total Row, Last Column and Banded Columns unchecked. In OOXML terms that is the bitmask 0x04A0.
They are applied whenever you omit tableStyleOptions, and any options you do pass are merged on top rather than replacing the whole set — so tableStyleOptions: { totalRow: true } turns on the Total Row and leaves the other five at their defaults.
The spec and Word disagree here, which is why the defaults are always written out explicitly.
ECMA-376 says a table with no tblLook element gets 0x0000 (everything off), but Word instead
assumes 0x04A0 (MS-OI29500
§17.4.55).
Emitting the values keeps every renderer agreeing with what Word displays.
To opt out of a default, set it explicitly — for example tableStyleOptions: { headerRow: false } to drop the header row formatting.
Examples
Source: https://github.com/dolanmiu/docx/blob/master/demo/4-basic-table.ts
Custom borders
Example showing how to add colorful borders to tables
Source: https://github.com/dolanmiu/docx/blob/master/demo/20-table-cell-borders.ts
Adding images
Example showing how to add images to tables
Source: https://github.com/dolanmiu/docx/blob/master/demo/24-images-to-table-cell.ts
Source: https://github.com/dolanmiu/docx/blob/master/demo/36-image-to-table-cell.ts
Alignment of text in a cell
Example showing how align text in a table cell
Source: https://github.com/dolanmiu/docx/blob/master/demo/31-tables.ts
Shading
Example showing merging of columns and rows and shading
Source: https://github.com/dolanmiu/docx/blob/master/demo/32-merge-and-shade-table-cells.ts
Source: https://github.com/dolanmiu/docx/blob/master/demo/41-merge-table-cells-2.ts
Merging columns
Example showing merging of columns and rows
Source: https://github.com/dolanmiu/docx/blob/master/demo/43-images-to-table-cell-2.ts