Build a table in a story
A recipe for authoring an IDML Table — nest it on a paragraph, declare its grid with row, column, and cell counts, then give each Cell its own paragraph.
A table in IDML is nested on a paragraph, not placed as a top-level object.
In short: to author a table by hand you nest a Table element inside a
CharacterStyleRange, declare the grid with a few row and column counts, list the
tracks, then give every cell its own little paragraph. The table draws wherever the
text flow reaches it, so the simplest host is an empty paragraph in an otherwise
blank story. This recipe builds a two-column, three-row table from scratch, naming
each element and attribute exactly as it appears in the XML.
The recipe
- Find a host paragraph. A
Tablelives inside aCharacterStyleRange, which lives inside aParagraphStyleRange, inside aStory. The table draws where the text flow reaches it. If you only need a table, an empty paragraph in an otherwise blank story is enough to carry it. - Declare the grid on the
Tableelement. SetHeaderRowCount,BodyRowCount, andFooterRowCount— they add up to the total row count — andColumnCount. In the example,HeaderRowCount="1"plusBodyRowCount="2"makes three rows;ColumnCount="2"makes two columns. PointAppliedTableStyleat a table style (TableStyle/$ID/[Basic Table]is the built-in default). - List the rows, then the columns. Add one
<Row>per row and one<Column>per column.Nameis the zero-based index;SingleRowHeightandSingleColumnWidthsize the track in points. Order matters: allRowelements come before allColumnelements, before any cells. - Add one
<Cell>per grid position. Address each cell withName="col:row"— zero-indexed, column first. Cell0:0is the top-left header;1:2is the second column of the third row.RowSpanandColumnSpandefault to1. - Put a paragraph inside each cell. A cell's content is an ordinary
ParagraphStyleRange→CharacterStyleRange→Content, the same structure as story body text — just scoped to the cell. That's where the cell's text lives. - Paint and pad as needed.
FillColoron a cell fills its background (the header cells useColor/Black); the fourText*Insetattributes pad the content from the cell edges; the*EdgeStrokeColor/*EdgeStrokeWeightpairs draw the cell's borders.
Worked over a small table
The story below is a single empty paragraph that carries one Table: a header row
("Item", "Qty") and two body rows. Read its Stories/Story_ustory.xml part — every
element the recipe names is right there, in order.
A Table nested on a paragraph: three Rows, two Columns, and six Cells, each addressed by Name="col:row" and holding 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>
Things to get right
- Counts and tracks must agree.
HeaderRowCount + BodyRowCount + FooterRowCounthas to equal the number of<Row>elements, andColumnCountthe number of<Column>elements. A mismatch is the most common reason a hand-authored table fails to build. - Cell
Nameiscolumn:row, notrow:column. It reads backwards from how you might say it aloud. Cell1:0is column 1, row 0 — the top-right header in a two-column table. - A cell with no
ParagraphStyleRangeis an empty cell, not a missing one. You still write the<Cell>element for every grid position; an empty cell just has no paragraph inside. - Spanning cells don't repeat. A cell with
ColumnSpan="2"covers two columns, so you write one<Cell>for the span and omit the position it absorbs — don't also emit the covered cell. - Header and footer rows repeat when the table breaks. That behaviour, and how a table splits across threaded frames, belongs to tables in the text flow.
For the full model — how rows, columns, and cells relate, and why a table is anchored on a paragraph at all — see Tables.
Frequently asked questions
Where does a Table element live in the IDML structure?
A Table is nested inside a CharacterStyleRange, which sits inside a
ParagraphStyleRange, inside a Story. It is not a top-level object — it rides on a
paragraph and draws where the text flow reaches it, so an empty paragraph in a blank
story is enough to carry one.
How do I size a table's rows and columns?
You declare the grid on the Table element with HeaderRowCount, BodyRowCount,
FooterRowCount, and ColumnCount, then list one <Row> and one <Column> per
track. SingleRowHeight and SingleColumnWidth set each track's size in points. The
row counts must add up to the number of <Row> elements, and ColumnCount must
match the number of <Column> elements, or the table fails to build.
How are individual cells addressed?
Each <Cell> carries a Name of the form column:row, zero-indexed and column
first — so 0:0 is the top-left cell and 1:2 is the second column of the third
row. You write one <Cell> per grid position; a cell with no ParagraphStyleRange
is simply empty, not missing.
What happens to a table when it breaks across frames? Header and footer rows repeat at the top of each fragment when a table splits across threaded frames. That behaviour belongs to the reference — see tables in the text flow.
Cookbook
Task recipes for authoring IDML by hand — build a table, apply a gradient, place an image — each grounded in a validated example and cross-linked to the reference.
Apply a gradient fill
A recipe for defining a Gradient swatch with two GradientStops and using it as a shape's fill by pointing FillColor at the gradient's Self id.