Work in progress — this reference is being written in the open. Unfinished pages are excluded from search engines.
Paged · IDML Reference
Cookbook

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.

Pro· how-to

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

  1. Find a host paragraph. A Table lives inside a CharacterStyleRange, which lives inside a ParagraphStyleRange, inside a Story. 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.
  2. Declare the grid on the Table element. Set HeaderRowCount, BodyRowCount, and FooterRowCount — they add up to the total row count — and ColumnCount. In the example, HeaderRowCount="1" plus BodyRowCount="2" makes three rows; ColumnCount="2" makes two columns. Point AppliedTableStyle at a table style (TableStyle/$ID/[Basic Table] is the built-in default).
  3. List the rows, then the columns. Add one <Row> per row and one <Column> per column. Name is the zero-based index; SingleRowHeight and SingleColumnWidth size the track in points. Order matters: all Row elements come before all Column elements, before any cells.
  4. Add one <Cell> per grid position. Address each cell with Name="col:row" — zero-indexed, column first. Cell 0:0 is the top-left header; 1:2 is the second column of the third row. RowSpan and ColumnSpan default to 1.
  5. Put a paragraph inside each cell. A cell's content is an ordinary ParagraphStyleRangeCharacterStyleRangeContent, the same structure as story body text — just scoped to the cell. That's where the cell's text lives.
  6. Paint and pad as needed. FillColor on a cell fills its background (the header cells use Color/Black); the four Text*Inset attributes pad the content from the cell edges; the *EdgeStrokeColor / *EdgeStrokeWeight pairs 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 + FooterRowCount has to equal the number of <Row> elements, and ColumnCount the number of <Column> elements. A mismatch is the most common reason a hand-authored table fails to build.
  • Cell Name is column:row, not row:column. It reads backwards from how you might say it aloud. Cell 1:0 is column 1, row 0 — the top-right header in a two-column table.
  • A cell with no ParagraphStyleRange is 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.

On this page