Rows, columns, and cells
The Row, Column, and Cell children of a table — track sizes, the col:row cell address, merged cells via RowSpan and ColumnSpan, per-cell insets and strokes, and the text inside a cell.
A <Table> carries three kinds of children — <Row>, <Column>, and <Cell> — that fill in the grid its counts declared.
In short: The <Row> and <Column> children size a table's tracks: a
<Column> carries a width, a <Row> carries height constraints, and each is
named by its zero-based index. The <Cell> children hold the content and most of
the formatting — each cell names its grid position with Name="col:row", can span
rows or columns to merge, and holds its own paragraphs of text padded in by its
insets. This page is the attribute reference for those three children.
A <Table> carries three kinds of children that fill in the grid its
counts declared: one <Row> per row, one
<Column> per column, and one <Cell> per occupied grid position. The rows and
columns size the tracks; the cells hold the content and most of the formatting.
The example below is a three-row, two-column table — a one-row header over two body rows — with each cell holding a one-word paragraph. It is the structure the rest of this page references.
A table inside a story: HeaderRowCount and BodyRowCount set the grid, Row and Column give the tracks, and each Cell holds its own paragraph.
Stories/Story_ustory.xml<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<idPkg:Story xmlns:idPkg="http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging" DOMVersion="20.0">
<Story Self="ustory">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Table Self="utable" HeaderRowCount="1" FooterRowCount="0" BodyRowCount="2" ColumnCount="2"
AppliedTableStyle="TableStyle/$ID/[Basic Table]"
TopBorderStrokeColor="Color/Black" TopBorderStrokeWeight="1"
BottomBorderStrokeColor="Color/Black" BottomBorderStrokeWeight="1"
LeftBorderStrokeColor="Color/Black" LeftBorderStrokeWeight="1"
RightBorderStrokeColor="Color/Black" RightBorderStrokeWeight="1">
<Row Self="urow0" Name="0" SingleRowHeight="24"/>
<Row Self="urow1" Name="1" SingleRowHeight="24"/>
<Row Self="urow2" Name="2" SingleRowHeight="24"/>
<Column Self="ucol0" Name="0" SingleColumnWidth="120"/>
<Column Self="ucol1" Name="1" SingleColumnWidth="120"/>
<Cell Self="ucell00" Name="0:0" RowSpan="1" ColumnSpan="1"
TextTopInset="2" TextLeftInset="3" TextBottomInset="2" TextRightInset="3"
AppliedCellStyle="CellStyle/$ID/[None]" FillColor="Color/Black"
BottomEdgeStrokeColor="Color/Black" BottomEdgeStrokeWeight="1"
RightEdgeStrokeColor="Color/Black" RightEdgeStrokeWeight="1">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Content>Item</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
</Cell>
<Cell Self="ucell10" Name="1:0" RowSpan="1" ColumnSpan="1"
TextTopInset="2" TextLeftInset="3" TextBottomInset="2" TextRightInset="3"
AppliedCellStyle="CellStyle/$ID/[None]" FillColor="Color/Black"
BottomEdgeStrokeColor="Color/Black" BottomEdgeStrokeWeight="1">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Content>Qty</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
</Cell>
<Cell Self="ucell01" Name="0:1" RowSpan="1" ColumnSpan="1"
TextTopInset="2" TextLeftInset="3" TextBottomInset="2" TextRightInset="3"
AppliedCellStyle="CellStyle/$ID/[None]"
BottomEdgeStrokeColor="Color/Black" BottomEdgeStrokeWeight="1"
RightEdgeStrokeColor="Color/Black" RightEdgeStrokeWeight="1">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Content>Paper</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
</Cell>
<Cell Self="ucell11" Name="1:1" RowSpan="1" ColumnSpan="1"
TextTopInset="2" TextLeftInset="3" TextBottomInset="2" TextRightInset="3"
AppliedCellStyle="CellStyle/$ID/[None]"
BottomEdgeStrokeColor="Color/Black" BottomEdgeStrokeWeight="1">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Content>12</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
</Cell>
<Cell Self="ucell02" Name="0:2" RowSpan="1" ColumnSpan="1"
TextTopInset="2" TextLeftInset="3" TextBottomInset="2" TextRightInset="3"
AppliedCellStyle="CellStyle/$ID/[None]"
RightEdgeStrokeColor="Color/Black" RightEdgeStrokeWeight="1">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Content>Toner</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
</Cell>
<Cell Self="ucell12" Name="1:2" RowSpan="1" ColumnSpan="1"
TextTopInset="2" TextLeftInset="3" TextBottomInset="2" TextRightInset="3"
AppliedCellStyle="CellStyle/$ID/[None]">
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/$ID/[No paragraph style]">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/$ID/[No character style]">
<Content>4</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
</Cell>
</Table>
</CharacterStyleRange>
</ParagraphStyleRange>
</Story>
</idPkg:Story>
A note on the validator counts: the renderer reports this package as one
paragraph and zero runs. That single paragraph is the host paragraph the
<Table> rides on — its run is consumed by the table, so it contributes no text
run of its own. The six cell paragraphs are laid out inside the table's own grid
pipeline and are not added to the story's paragraph and run totals.
Columns size the horizontal tracks
A <Column> is an empty element: it has no content, only a width. Columns appear
in left-to-right order, and each one's Name is its zero-based index.
| Attribute · Column | Type / values | Support | Notes |
|---|---|---|---|
| Self | string id | Supported | The column id. |
| Name | string (zero-based index) | Supported | The column index as a string: "0" for the first column, "1" for the next, and so on. This is the column half of a cell’s col:row address. |
| SingleColumnWidth | double (pt) | Supported | The column’s width in points. A column with no width contributes 0 to the table’s total width. |
Rows size the vertical tracks
A <Row> is likewise empty — it carries the row's height constraints. Rows appear
top-to-bottom, header rows first, then body, then footer, matching the <Table>
counts. Each row's Name is its zero-based index across the whole table.
| Attribute · Row | Type / values | Support | Notes |
|---|---|---|---|
| Self | string id | Supported | The row id. |
| Name | string (zero-based index) | Supported | The row index as a string, counting from 0 at the top across all regions. This is the row half of a cell’s col:row address. |
| SingleRowHeight | double (pt) | Supported | The row’s nominal height in points. The renderer grows a row past this when its cell content needs more space (and a MaximumHeight is not in the way). |
| MinimumHeight | double (pt) | Supported | A floor the row will not shrink below. The effective height is the larger of SingleRowHeight and MinimumHeight, then grown to fit content. |
| MaximumHeight | double (pt) | Supported | A ceiling the row will not grow past. Absent means unbounded — IDML writes a large sentinel when there is no limit, which the parser treats as no limit. |
AutoGrow, KeepWithNextRow, and StartRow are stored by IDML on a <Row> but
are not read here; content-driven row growth is on by default, and the
keep-together / forced-start behaviours are not yet honoured.
Cells hold the content
A <Cell> is where the grid meets the text. Each cell names its position with
Name="col:row" (both zero-based), so a cell at column 1 of row 0 is
Name="1:0". Cells are serialised in column-major order — every cell in column 0
top-to-bottom, then column 1, and so on — but their Name is what places them, so
the serialisation order does not matter to the result.
Position and span
| Attribute · Cell | Type / values | Support | Notes |
|---|---|---|---|
| Self | string id | Supported | The cell id. |
| Name | string ("col:row") | Supported | The cell’s grid address — column index, a colon, row index, both zero-based. This, not the document order, is what positions the cell. |
| RowSpan | int | Supported | How many rows the cell occupies, starting at its row. Defaults to 1. Values above 1 merge cells vertically — see below. |
| ColumnSpan | int | Supported | How many columns the cell occupies, starting at its column. Defaults to 1. Values above 1 merge cells horizontally. |
Merged cells
A merged cell is just a cell with a span greater than 1. A cell with
ColumnSpan="2" occupies its own column and the one to its right; a cell with
RowSpan="3" occupies its row and the two below. The covered grid positions have
no <Cell> element of their own — they are absorbed by the spanning cell. This is
why the number of <Cell> elements is usually fewer than rows × columns: every
merge removes the cells it swallows.
When a row-spanning cell needs more height than its rows provide, the renderer adds the shortfall to the last row of the span; the earlier rows keep their declared heights.
Insets and the cell's text
A cell's content is ordinary text: one or more <ParagraphStyleRange> children,
exactly as in the body of a story. The cell's four insets pad that text in from
the cell edges.
| Attribute · Cell | Type / values | Support | Notes |
|---|---|---|---|
| TextTopInset / TextLeftInset / TextBottomInset / TextRightInset | double (pt) | Supported | Padding between the cell edges and its text, per side, in points. Default 0. Read directly off the cell, not from the cell style. |
| AppliedCellStyle | string (CellStyle id) | Parsed, not yet rendered | The cell style the cell applies. The cell style’s fill and per-edge strokes are resolved as a fallback when the cell omits its own; insets and the cell’s starting paragraph style are not yet read from the style. See the note below. |
| FirstBaselineOffset | Ascent | CapHeight | LeadingOffset | EmboxHeight | XHeight | FixedHeight | Parsed, not yet rendered | Where the first line of cell text drops from the cell’s top inset. Captured; the renderer uses Ascent semantics today. |
| MinimumFirstBaselineOffset | double (pt) | Parsed, not yet rendered | The fixed baseline drop used when FirstBaselineOffset is FixedHeight. Parsed for completeness. |
AppliedCellStyle resolution is partial: the renderer reads the resolved cell
style's fill colour and per-edge strokes as fallbacks, but a cell style's own
insets, starting paragraph style, and diagonals are not yet read — so cell padding
comes from the TextInset attributes on the cell, not from its style. The detail
of which style attributes are read is on
table and cell styles.
Fill and per-edge strokes
A cell can paint its own background and its own four edge strokes. InDesign
serialises an explicit stroke on every cell edge when a table-style divider
applies, even when the cell's AppliedCellStyle is [None] — so honouring these
per-cell edges is what makes ordinary gridlines appear. An inline value on the
cell wins over whatever its cell style would contribute.
| Attribute · Cell | Type / values | Support | Notes |
|---|---|---|---|
| FillColor | string (swatch id) | Supported | The cell’s background fill. A reference into Resources/Graphic.xml; wins over the resolved cell style’s fill. |
| TopEdgeStrokeColor / BottomEdgeStrokeColor / LeftEdgeStrokeColor / RightEdgeStrokeColor | string (swatch id) | Supported | Per-edge stroke paint. Each drawn edge wins over the cell style’s same edge. |
| TopEdgeStrokeWeight / BottomEdgeStrokeWeight / LeftEdgeStrokeWeight / RightEdgeStrokeWeight | double (pt) | Supported | Per-edge stroke weight in points. |
| TopEdgeStrokeTint / … / RightEdgeStrokeTint | double (0–100%) | Supported | Per-edge stroke tint percentage. |
Diagonal lines
A cell can draw one or both diagonal lines across itself. The parser reads InDesign's diagonal attributes; the renderer emits a stroke for each diagonal that is drawn.
| Attribute · Cell | Type / values | Support | Notes |
|---|---|---|---|
| LeftLineDrawn | boolean | Supported | Draws the diagonal that runs top-left to bottom-right. |
| RightLineDrawn | boolean | Supported | Draws the diagonal that runs top-right to bottom-left. |
| LeftLineStrokeColor / RightLineStrokeColor | string (swatch id) | Supported | Paint for each diagonal. |
| LeftLineStrokeWeight / RightLineStrokeWeight | double (pt) | Supported | Weight for each diagonal. |
| DiagonalLineInFront | boolean | Supported | When true, the diagonal paints on top of the cell content; otherwise behind it. |
VerticalJustification (TopAlign, CenterAlign, BottomAlign, JustifyAlign)
and RotationAngle are stored on a <Cell> but are not read here — cell content
sits at the top of the cell and is not rotated.
Frequently asked questions
How does a <Cell> know which grid position it occupies?
Each cell names its position with Name="col:row", both zero-based — so a cell at
column 1 of row 0 is Name="1:0". Cells are serialised in column-major order, but
the Name is what places them, so the document order does not affect the result.
How are merged cells represented?
A merged cell is a cell with a RowSpan or ColumnSpan greater than 1. The grid
positions it covers have no <Cell> element of their own — they are absorbed by
the spanning cell — which is why a table usually has fewer <Cell> elements than
rows × columns.
Where does a cell's text padding come from?
From the four TextInset attributes (TextTopInset, TextLeftInset,
TextBottomInset, TextRightInset) read directly off the <Cell>, defaulting to
0. A cell style's own insets are not yet read, so padding comes from the cell, not
its AppliedCellStyle.
Why does the validator report the table example as one paragraph and zero runs?
The single paragraph is the host paragraph the <Table> rides on; its run is
consumed by the table, so it contributes no text run. The cell paragraphs are laid
out inside the table's own grid pipeline and are not added to the story's paragraph
and run totals.
The table model
The Table element and its attributes — the row and column counts that define the grid, the outer border strokes, and the alternating row and column divider rules.
Tables in the text flow
What it means for a table to be anchored in a story's paragraph — how it draws where the flow reaches it, breaks across threaded frames, and repeats its header and footer rows.