# Table Pattern — LLM Reference This document teaches how to build table-like layouts using `Row` and `Column` components. Since no dedicated `Table` component exists, you compose tables by nesting `Row` (horizontal arrangement) inside `Column` (vertical arrangement), all within a `Container`. --- ## Core Concept — Correct Nesting ``` ContainerComponent ← email width container (fixed width only) └── ColumnComponent ← vertical stacking container (required) ├── RowComponent ← table row (horizontal) │ ├── ColumnComponent ← table cell │ └── ColumnComponent ← table cell ├── RowComponent ← table row (horizontal) │ ├── ColumnComponent ← table cell │ └── ColumnComponent ← table cell └── RowComponent ← table row (horizontal) └── ... ``` **Critical:** - `Row` must always be a child of `Column`, never directly inside `Container` - `Container` uses `widthType: "fixed"` only (no `"full"` value) — tables require a fixed pixel width | Component | Role | |---|---| | `ContainerComponent` | Fixed-width email container (e.g., `600px`) | | `ColumnComponent` (parent) | Vertical stacking container — holds all table rows | | `RowComponent` | Represents a **table row** — arranges cells horizontally | | `ColumnComponent` (child of Row) | Represents a **table cell** — contains content | --- ## Row Height Consistency To ensure all rows in a table have the same height, apply the `height` property on `Row` components whenever necessary. This prevents uneven row heights caused by varying content lengths across cells. ```json { "id": "consistent-height-row", "type": "RowComponent", "config": { "layoutColumns": ["33%", "34%", "33%"], "gap": "0px", "fillWidth": true, "height": "60px" }, "children": [...] } ``` **When to use `height`:** - Cells contain content of different lengths (e.g., short text vs. multi-line text) - Images or media of varying sizes appear in the same row - Ensuring visual alignment across complex table layouts **Best practice:** Set the same `height` value on all `Row` components within a table to guarantee uniform row dimensions. --- ## Border Application on Entire Row When there is a high possibility that row heights are not even, borders must be applied on the **entire row** (using `Row` configuration) rather than on individual cells. This prevents broken or misaligned border lines that occur when cells have different heights. ### Incorrect — Border on Cells (Height Mismatch Risk) ```json { "id": "bad-row", "type": "RowComponent", "config": { "layoutColumns": ["50%", "50%"], "gap": "0px", "fillWidth": true }, "children": [ { "id": "cell-1", "type": "ColumnComponent", "config": { "padding": "12px", "border": { "bottom": { "width": "1px", "style": "solid", "color": "#cbd5e1" } } }, "children": [...] }, { "id": "cell-2", "type": "ColumnComponent", "config": { "padding": "12px", "border": { "bottom": { "width": "1px", "style": "solid", "color": "#cbd5e1" } } }, "children": [...] } ] } ``` ### Correct — Border on Entire Row ```json { "id": "good-row", "type": "RowComponent", "config": { "layoutColumns": ["50%", "50%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#cbd5e1" } } }, "children": [ { "id": "cell-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "id": "cell-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] } ] } ``` **Why row-level borders are safer:** - The border spans the full width of the row regardless of individual cell heights - No gaps or breaks appear when cell content heights differ - Maintains visual integrity across all email clients **When to use row borders vs. cell borders:** | Scenario | Recommendation | |---|---| | Uneven row heights possible | Apply border on `Row` component | | All cells have identical content height | Cell borders acceptable | | Table has complex responsive behavior | Row borders preferred | | Borders required on all four sides of table | Use row borders for horizontal lines, container border for outer frame | --- ## Basic Table Structure ```json { "id": "table-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" } }, "children": [ { "id": "table-column-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "header-row", "type": "RowComponent", "config": { "layoutColumns": "equal", "gap": "0px", "fillWidth": true, "backgroundColor": "#1e293b", "height": "50px" }, "children": [ { "id": "header-cell-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [ { "id": "header-text-1", "type": "TextComponent", "config": { "text": "Column A", "color": "#ffffff", "fontWeight": "bold" } } ] }, { "id": "header-cell-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [ { "id": "header-text-2", "type": "TextComponent", "config": { "text": "Column B", "color": "#ffffff", "fontWeight": "bold" } } ] } ] }, { "id": "data-row-1", "type": "RowComponent", "config": { "layoutColumns": "equal", "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e2e8f0" } } }, "children": [ { "id": "cell-1-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [ { "id": "text-1-1", "type": "TextComponent", "config": { "text": "Row 1, Cell A" } } ] }, { "id": "cell-1-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [ { "id": "text-1-2", "type": "TextComponent", "config": { "text": "Row 1, Cell B — additional content that might wrap to multiple lines" } } ] } ] }, { "id": "data-row-2", "type": "RowComponent", "config": { "layoutColumns": "equal", "gap": "0px", "fillWidth": true }, "children": [ { "id": "cell-2-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [ { "id": "text-2-1", "type": "TextComponent", "config": { "text": "Row 2, Cell A" } } ] }, { "id": "cell-2-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [ { "id": "text-2-2", "type": "TextComponent", "config": { "text": "Row 2, Cell B" } } ] } ] } ] } ] } ``` --- ## Controlling Column Widths with `layoutColumns` `layoutColumns` on `Row` determines how child `Column` components share space. **Use the same `layoutColumns` value for every row** to maintain column alignment. ### Equal Columns (2, 3, or more) ```json { "id": "row-3-columns", "type": "RowComponent", "config": { "layoutColumns": "equal", "gap": "0px", "fillWidth": true, "height": "60px" }, "children": [ { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] } ] } ``` Each cell gets `33.33%` width. ### Proportional Columns (Manual Percentages) ```json { "id": "row-asymmetric", "type": "RowComponent", "config": { "layoutColumns": ["25%", "50%", "25%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e2e8f0" } } }, "children": [ { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] } ] } ``` ### Fixed Width Columns ```json { "id": "row-fixed", "type": "RowComponent", "config": { "layoutColumns": ["100px", "auto", "150px"], "gap": "0px", "fillWidth": true, "height": "50px" }, "children": [ { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] } ] } ``` - First cell: fixed `100px` - Second cell: fills remaining space (`auto`) - Third cell: fixed `150px` --- ## Complete Table Example — 3×3 with Row Borders ```json { "id": "complete-table-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" } }, "children": [ { "id": "table-vertical-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "header-row", "type": "RowComponent", "config": { "layoutColumns": ["30%", "40%", "30%"], "gap": "0px", "fillWidth": true, "backgroundColor": "#1e293b", "height": "55px" }, "children": [ { "id": "header-cell-1", "type": "ColumnComponent", "config": { "padding": "16px" }, "children": [{ "id": "header-text-1", "type": "TextComponent", "config": { "text": "Product", "color": "#ffffff", "fontWeight": "bold" } }] }, { "id": "header-cell-2", "type": "ColumnComponent", "config": { "padding": "16px" }, "children": [{ "id": "header-text-2", "type": "TextComponent", "config": { "text": "Description", "color": "#ffffff", "fontWeight": "bold" } }] }, { "id": "header-cell-3", "type": "ColumnComponent", "config": { "padding": "16px" }, "children": [{ "id": "header-text-3", "type": "TextComponent", "config": { "text": "Price", "color": "#ffffff", "fontWeight": "bold", "textAlign": "right" } }] } ] }, { "id": "row-1", "type": "RowComponent", "config": { "layoutColumns": ["30%", "40%", "30%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e2e8f0" } } }, "children": [ { "id": "cell-1-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-1-1", "type": "TextComponent", "config": { "text": "Basic Tee" } }] }, { "id": "cell-1-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-1-2", "type": "TextComponent", "config": { "text": "Cotton t-shirt, regular fit" } }] }, { "id": "cell-1-3", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-1-3", "type": "TextComponent", "config": { "text": "$29.00", "textAlign": "right" } }] } ] }, { "id": "row-2", "type": "RowComponent", "config": { "layoutColumns": ["30%", "40%", "30%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e2e8f0" } } }, "children": [ { "id": "cell-2-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-2-1", "type": "TextComponent", "config": { "text": "Premium Hoodie" } }] }, { "id": "cell-2-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-2-2", "type": "TextComponent", "config": { "text": "Fleece-lined, zip-up hoodie with extra warm lining for cold weather" } }] }, { "id": "cell-2-3", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-2-3", "type": "TextComponent", "config": { "text": "$89.00", "textAlign": "right" } }] } ] }, { "id": "footer-row", "type": "RowComponent", "config": { "layoutColumns": ["30%", "40%", "30%"], "gap": "0px", "fillWidth": true, "backgroundColor": "#f8fafc", "height": "50px" }, "children": [ { "id": "footer-cell-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "footer-text-1", "type": "TextComponent", "config": { "text": "Total" } }] }, { "id": "footer-cell-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "footer-text-2", "type": "TextComponent", "config": { "text": "2 items" } }] }, { "id": "footer-cell-3", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "footer-text-3", "type": "TextComponent", "config": { "text": "$118.00", "textAlign": "right", "fontWeight": "bold" } }] } ] } ] } ] } ``` --- ## Full Grid Borders (All Sides) — Row-Level Approach When borders are needed on all sides of a table with potential height mismatches, apply horizontal borders on `Row` components and use a container border for the outer frame. ```json { "id": "bordered-table-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" }, "border": { "all": { "width": "1px", "style": "solid", "color": "#cbd5e1" } } }, "children": [ { "id": "bordered-table-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "row-1", "type": "RowComponent", "config": { "layoutColumns": ["33%", "34%", "33%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#cbd5e1" } } }, "children": [ { "id": "cell-1", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-1", "type": "TextComponent", "config": { "text": "Cell 1" } }] }, { "id": "cell-2", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-2", "type": "TextComponent", "config": { "text": "Cell 2 with longer content that might wrap" } }] }, { "id": "cell-3", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-3", "type": "TextComponent", "config": { "text": "Cell 3" } }] } ] }, { "id": "row-2", "type": "RowComponent", "config": { "layoutColumns": ["33%", "34%", "33%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#cbd5e1" } } }, "children": [ { "id": "cell-4", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-4", "type": "TextComponent", "config": { "text": "Cell 4" } }] }, { "id": "cell-5", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-5", "type": "TextComponent", "config": { "text": "Cell 5" } }] }, { "id": "cell-6", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-6", "type": "TextComponent", "config": { "text": "Cell 6 — even more text that causes this cell to be taller than others in the same row" } }] } ] } ] } ] } ``` **Note:** The container border wraps the entire table, while row borders provide horizontal lines that span the full width regardless of individual cell heights. --- ## Simulating Rowspan Since `Row` does not support `rowspan` natively, nest multiple `Row` components inside a `Column` on one side. ```json { "id": "rowspan-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" } }, "children": [ { "id": "rowspan-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "rowspan-row", "type": "RowComponent", "config": { "layoutColumns": ["30%", "70%"], "gap": "0px", "fillWidth": true }, "children": [ { "id": "left-span-cell", "type": "ColumnComponent", "config": { "padding": "16px", "backgroundColor": "#fef3c7" }, "children": [ { "id": "span-content", "type": "TextComponent", "config": { "text": "This spans both rows vertically" } } ] }, { "id": "right-group-cell", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "sub-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "100%", "childrenConstraints": { "widthDistributionType": "equals" } }, "children": [ { "id": "sub-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "sub-row-1", "type": "RowComponent", "config": { "layoutColumns": ["100%"], "gap": "0px", "fillWidth": true }, "children": [ { "id": "top-right-cell", "type": "ColumnComponent", "config": { "padding": "12px", "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e5e7eb" } } }, "children": [{ "id": "text-right-1", "type": "TextComponent", "config": { "text": "Top right row" } }] } ] }, { "id": "sub-row-2", "type": "RowComponent", "config": { "layoutColumns": ["100%"], "gap": "0px", "fillWidth": true }, "children": [ { "id": "bottom-right-cell", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-right-2", "type": "TextComponent", "config": { "text": "Bottom right row" } }] } ] } ] } ] } ] } ] } ] } ] } ``` --- ## Shopping Cart Table Example ```json { "id": "cart-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" } }, "children": [ { "id": "cart-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "cart-header", "type": "RowComponent", "config": { "layoutColumns": ["40%", "15%", "20%", "25%"], "gap": "0px", "fillWidth": true, "backgroundColor": "#111827", "height": "50px" }, "children": [ { "id": "header-product", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-product", "type": "TextComponent", "config": { "text": "Product", "color": "#ffffff", "fontWeight": "bold" } }] }, { "id": "header-qty", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-qty", "type": "TextComponent", "config": { "text": "Qty", "color": "#ffffff", "fontWeight": "bold", "textAlign": "center" } }] }, { "id": "header-price", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-price", "type": "TextComponent", "config": { "text": "Price", "color": "#ffffff", "fontWeight": "bold", "textAlign": "right" } }] }, { "id": "header-total", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "text-total", "type": "TextComponent", "config": { "text": "Total", "color": "#ffffff", "fontWeight": "bold", "textAlign": "right" } }] } ] }, { "id": "cart-item-1", "type": "RowComponent", "config": { "layoutColumns": ["40%", "15%", "20%", "25%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e5e7eb" } } }, "children": [ { "id": "item1-product", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item1-name", "type": "TextComponent", "config": { "text": "Wireless Mouse" } }] }, { "id": "item1-qty", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item1-qty-num", "type": "TextComponent", "config": { "text": "2", "textAlign": "center" } }] }, { "id": "item1-price", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item1-price-val", "type": "TextComponent", "config": { "text": "$25.00", "textAlign": "right" } }] }, { "id": "item1-total", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item1-total-val", "type": "TextComponent", "config": { "text": "$50.00", "textAlign": "right", "fontWeight": "bold" } }] } ] }, { "id": "cart-item-2", "type": "RowComponent", "config": { "layoutColumns": ["40%", "15%", "20%", "25%"], "gap": "0px", "fillWidth": true, "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e5e7eb" } } }, "children": [ { "id": "item2-product", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item2-name", "type": "TextComponent", "config": { "text": "Mechanical Keyboard with RGB lighting and extra keycaps" } }] }, { "id": "item2-qty", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item2-qty-num", "type": "TextComponent", "config": { "text": "1", "textAlign": "center" } }] }, { "id": "item2-price", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item2-price-val", "type": "TextComponent", "config": { "text": "$129.00", "textAlign": "right" } }] }, { "id": "item2-total", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "item2-total-val", "type": "TextComponent", "config": { "text": "$129.00", "textAlign": "right", "fontWeight": "bold" } }] } ] }, { "id": "cart-footer", "type": "RowComponent", "config": { "layoutColumns": ["40%", "15%", "20%", "25%"], "gap": "0px", "fillWidth": true, "backgroundColor": "#f8fafc", "height": "50px" }, "children": [ { "id": "footer-empty", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [] }, { "id": "footer-label", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "footer-label-text", "type": "TextComponent", "config": { "text": "Subtotal:", "fontWeight": "bold", "textAlign": "right" } }] }, { "id": "footer-price", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [] }, { "id": "footer-total", "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [{ "id": "footer-total-text", "type": "TextComponent", "config": { "text": "$179.00", "textAlign": "right", "fontWeight": "bold" } }] } ] } ] } ] } ``` --- ## Quick Reference: Table Template ```json { "id": "table-template", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" } }, "children": [ { "id": "table-rows-wrapper", "type": "ColumnComponent", "config": { "padding": "0px" }, "children": [ { "id": "row-1", "type": "RowComponent", "config": { "layoutColumns": ["25%", "50%", "25%"], "gap": "0px", "fillWidth": true, "height": "60px", "border": { "bottom": { "width": "1px", "style": "solid", "color": "#e2e8f0" } } }, "children": [ { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] } ] }, { "id": "row-2", "type": "RowComponent", "config": { "layoutColumns": ["25%", "50%", "25%"], "gap": "0px", "fillWidth": true, "height": "60px" }, "children": [ { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] }, { "type": "ColumnComponent", "config": { "padding": "12px" }, "children": [...] } ] } ] } ] } ``` --- ## Key Rules for Table Construction | Rule | Explanation | |---|---| | **Container → Column → Row** | Never put `Row` directly inside `Container`. Always wrap with a `Column`. | | **Container uses `widthType: "fixed"` only** | Tables require a fixed pixel width (e.g., `600px`). No `"full"` value. | | **Every table row is a `Row`** | `Row` provides horizontal arrangement of cells. | | **Every cell is a `Column`** | `Column` stacks content vertically within a cell. | | **Use `layoutColumns` on every row** | Ensures column widths stay consistent across all rows. | | **Same `layoutColumns` array for all rows** | Copy the exact same `layoutColumns` value across every row in the table. | | **Set `gap: "0px"` for tables** | Table cells should have no gap; use `Column.padding` for internal spacing. | | **Set `fillWidth: true` on table rows** | Ensures the row fills the container width for proper column distribution. | | **`Container.width` sets email width** | Use `width` on `Container` (with `widthType: "fixed"`) to control the overall table width. | | **Use `height` on rows for consistency** | Apply `height` property on `Row` components when uneven row heights are possible. | | **Apply borders on rows when heights may vary** | When there is a high possibility of uneven row heights, use `Row` borders instead of cell borders. |