# Column Component — LLM Reference
`Column` is a **vertical stacking primitive** that wraps a single cell of content within a `Container` or `Row`. It arranges its children top-to-bottom, handles padding, background styling, borders, alignment, and an optional `maxWidth` constraint that works across modern clients and Outlook Classic. It is the innermost structural layer before leaf components (Text, Image, Button, etc.).
---
## Position in the Document Tree
```
DocumentTree
└── Section ← full-width band
└── Container ← horizontal column layout, email width
└── Column ← vertical child stacking within a cell
└── Text / Image / Button / ...
```
A `Column` typically lives as a direct child of a `Container` column slot, or inside a `Row`. It is never used as a root-level node in the `DocumentTree`.
---
## ComponentNode JSON Structure
```json
{
"id": "unique-string-id",
"type": "ColumnComponent",
"config": {
"padding": "24px",
"gap": "12px",
"alignItems": "center",
"justifyContent": "center",
"width": "100%",
"height": "200px",
"maxWidth": "480px",
"backgroundColor": "#ffffff",
"borderRadius": "8px",
"border": {
"width": "1px",
"style": "solid",
"color": "#e5e7eb"
},
"backgroundImage": {
"src": "https://example.com/bg.jpg",
"repeat": "no-repeat",
"size": "cover",
"position": "center center"
}
},
"children": []
}
```
---
## `ColumnConfig` — Full Property Reference
### Layout & Sizing
| Property | Type | Example | Description |
|---|---|---|---|
| `width` | `string` | `"100%"` | Width of the outer column table. Usually left unset — width is inherited from the parent cell. |
| `height` | `string` | `"200px"` | Fixed height applied to the outer table and `
`. Padding is inside this height. |
| `maxWidth` | `string` | `"480px"` | Caps the rendered content width. Uses a `
` + inner table pattern for Outlook Classic compatibility. See **`maxWidth` behavior** below. |
| `gap` | `string` | `"16px"` | Vertical space between children. Only takes effect when there are 2+ children. Rendered as a spacer `
` row. |
| `padding` | `string` | `"16px 24px"` | Inner padding. Does **not** add to `height` — it is contained within the declared height. |
### Alignment
> ⚠️ **Axis mapping is inverted relative to CSS Flexbox.** In this component, `justifyContent` controls the **vertical** axis and `alignItems` controls the **horizontal** axis. This is the opposite of standard CSS flex behavior.
| Property | Type | Controls | Options |
|---|---|---|---|
| `justifyContent` | `"start" \| "center" \| "end"` | **Vertical** alignment (`valign`) | `"start"` → top, `"center"` → middle, `"end"` → bottom |
| `alignItems` | `"start" \| "center" \| "end"` | **Horizontal** alignment (`align`) | `"start"` → left, `"center"` → center, `"end"` → right |
Both are applied to the inner padding `
` and to each child `
` in the gap wrapper.
### Visual
| Property | Type | Example | Description |
|---|---|---|---|
| `backgroundColor` | `string` | `"#f9fafb"` | Background fill color applied to the outer `
` |
| `borderRadius` | `string` | `"8px"` | Rounds all corners. Also applies `overflow: hidden` to clip background. |
| `border` | `BorderConfig` | See below | Border applied to the inner border-wrapper table |
| `backgroundImage` | `BackgroundImageType` | See below | Background image on the outer `
` |
---
## `maxWidth` Behavior
`maxWidth` is a special property that constrains the rendered content width in both modern email clients and Outlook Classic (Word rendering engine), which has no support for CSS `max-width`.
**How it works:**
- The outer column `
` stays at `width: 100%` — it always fills its parent cell
- Inside it, a `
` tag is rendered (Outlook Classic reads this as `margin: 0 auto`)
- Inside `
`, a table with `width={maxWidth}` as an HTML attribute — Outlook Classic respects this as a hard pixel cap
- Modern clients receive `max-width: {maxWidth}` as CSS on the same table and behave correctly
**When to use:** Use `maxWidth` when a Column sits inside a full-width parent but you want to constrain the readable text width (e.g. a 480px text column inside a 600px Section).
```json
"config": {
"width": "100%",
"maxWidth": "480px"
}
```
---
## `gap` Behavior
When `gap` is set and there are **2 or more children**, Column renders a gap wrapper table with alternating content rows and spacer rows:
```
child[0]
gap spacer
child[1]
gap spacer
child[2]
```
The spacer `
` has `height`, `lineHeight: "1px"`, `fontSize: "1px"` — the email-safe pattern for reliable vertical spacing in all clients.
When there is only **1 child**, `gap` has no effect — children are rendered directly without the wrapper table.
---
## `BorderConfig`
Specify either a **full border** (all sides) or **individual sides**. Do not mix both.
```json
// Full border — all sides
"border": {
"width": "1px",
"style": "solid",
"color": "#e5e7eb"
}
// Per-side — other sides explicitly set to "none" (Outlook-safe)
"border": {
"bottom": { "width": "2px", "style": "solid", "color": "#6366f1" }
}
```
Supported side keys: `"top"`, `"right"`, `"bottom"`, `"left"`.
Each side requires all three of: `width`, `style`, `color`.
When individual sides are used, all other sides are set to `"none"` explicitly to prevent Outlook Classic from rendering phantom black borders.
---
## `backgroundImage`
```json
"backgroundImage": {
"src": "https://example.com/texture.jpg",
"repeat": "no-repeat",
"size": "cover",
"position": "center center"
}
```
| Property | Options |
|---|---|
| `repeat` | `"no-repeat"`, `"repeat"`, `"repeat-x"`, `"repeat-y"` |
| `size` | `"auto"`, `"cover"`, `"contain"` |
| `position` | Any valid CSS `background-position` string |
Always pair with `backgroundColor` as an image-load fallback.
---
## React Usage
```tsx
import Column, { ColumnConfig } from './Column';
const config: ColumnConfig = {
padding: '24px',
gap: '16px',
alignItems: 'center',
justifyContent: 'start',
backgroundColor: '#ffffff',
};
```
The component is memoized via `arePropsEqual`. Pass stable `config` objects to avoid re-renders.
---
## Column vs Container vs Row — Key Differences
| | `Column` | `Container` | `Row` |
|---|---|---|---|
| **Direction** | **Vertical** (children stack top-to-bottom) | **Horizontal** (children placed left-to-right) | **Horizontal** (children placed left-to-right) |
| **Primary job** | Stack leaf components in a cell | Email-level column layout & width control | Inline child arrangement with alignment |
| **`gap` direction** | Vertical (between stacked children) | Horizontal (between columns) | Horizontal (between children) |
| **`maxWidth`** | ✓ Yes — Outlook-safe `
` + table pattern | ✗ No | ✗ No |
| **`alignItems` axis** | Horizontal (left/center/right) | Vertical (top/middle/bottom) | Vertical (top/middle/bottom) |
| **`justifyContent` axis** | Vertical (top/middle/bottom) | Horizontal (left/center/right) | Horizontal (left/center/right) |
| **Link wrapping** | ✗ No | ✗ No | ✓ Yes — `innerLink` |
| **Mobile stacking** | ✗ No (already vertical) | ✓ Yes — `shouldWrap` | ✓ Yes — `mobile.wrap` |
| **Border radius** | ✓ Yes | ✓ Yes | ✓ Yes |
| **Background image** | ✓ Yes | ✓ Yes | ✓ Yes |
---
## Common Patterns & Examples
### 1. Basic centered text column
```json
{
"id": "text-column",
"type": "ColumnComponent",
"config": {
"padding": "32px 24px",
"alignItems": "center",
"gap": "12px"
},
"children": []
}
```
---
### 2. Card-style column with border and radius
```json
{
"id": "card-column",
"type": "ColumnComponent",
"config": {
"padding": "24px",
"gap": "16px",
"backgroundColor": "#ffffff",
"borderRadius": "12px",
"border": {
"width": "1px",
"style": "solid",
"color": "#e5e7eb"
}
},
"children": []
}
```
---
### 3. Full-height column with vertically centered content
```json
{
"id": "centered-column",
"type": "ColumnComponent",
"config": {
"height": "240px",
"justifyContent": "center",
"alignItems": "center",
"padding": "16px"
},
"children": []
}
```
---
### 4. Constrained reading-width column
```json
{
"id": "article-column",
"type": "ColumnComponent",
"config": {
"width": "100%",
"maxWidth": "480px",
"padding": "24px 0",
"gap": "20px",
"alignItems": "start"
},
"children": []
}
```
---
### 5. Hero column with background image
```json
{
"id": "hero-column",
"type": "ColumnComponent",
"config": {
"height": "300px",
"justifyContent": "center",
"alignItems": "center",
"padding": "40px",
"backgroundColor": "#0f172a",
"backgroundImage": {
"src": "https://example.com/hero.jpg",
"repeat": "no-repeat",
"size": "cover",
"position": "center center"
}
},
"children": []
}
```
---
### 6. Left-border accent column (callout style)
```json
{
"id": "callout-column",
"type": "ColumnComponent",
"config": {
"padding": "16px 20px",
"backgroundColor": "#f0f9ff",
"gap": "8px",
"border": {
"left": { "width": "4px", "style": "solid", "color": "#0ea5e9" }
}
},
"children": []
}
```
---
### 7. Column inside a two-column Container layout
This is the typical full usage pattern — a `Container` with two child `Column`s:
```json
{
"id": "two-col-container",
"type": "ContainerComponent",
"config": {
"widthType": "fixed",
"width": "600px",
"childrenConstraints": {
"widthDistributionType": "ratio",
"ratio": { "mainChildIndex": 0, "value": [2, 3] }
},
"gap": "24px",
"padding": "24px"
},
"children": [
{
"id": "text-col",
"type": "ColumnComponent",
"config": {
"padding": "0",
"gap": "12px",
"justifyContent": "center"
},
"children": []
},
{
"id": "image-col",
"type": "ColumnComponent",
"config": {
"alignItems": "center",
"justifyContent": "center"
},
"children": []
}
]
}
```
---
## Data Bindings
`Column` supports the `bindings` property on the `ComponentNode`, alongside `id`, `type`, and `config`. Bindings connect this component to the Data Layer for dynamic rendering.
```json
{
"id": "feature-column",
"type": "ColumnComponent",
"bindings": {
"dataList": "features",
"itemAlias": "feature",
"visible": "feature.enabled === true",
"propertyMap": {
"config.backgroundColor": "feature.cardColor"
}
},
"config": {
"padding": "24px",
"gap": "12px",
"backgroundColor": "#ffffff",
"borderRadius": "8px"
},
"children": []
}
```
| Property | Description |
|---|---|
| `dataList` | Dot-path to an array in the Data Layer. Makes `Column` a repeater — one column rendered per item. |
| `itemAlias` | Name used by descendant components to reference the current iteration item (e.g. `"feature"` → `"feature.cardColor"`). |
| `visible` | JS expression evaluated against the Data Layer. Hides the entire column when falsy. |
| `propertyMap` | Maps `config` property paths to Data Layer paths (e.g. `"config.backgroundColor"` → `"feature.cardColor"`). |
---
## Rules & Constraints
- **`gap` only activates with 2+ children.** A single-child Column renders children directly without the gap wrapper table. Setting `gap` on a single-child Column is harmless but has no effect.
- **`height` is the total height including padding.** Unlike browser box-model behavior where `padding` adds to `height`, here padding is rendered inside the declared height. The inner `
` intentionally omits `height` to avoid double-counting.
- **`justifyContent` is vertical, `alignItems` is horizontal.** This is the opposite of CSS Flexbox. A model that applies Flexbox semantics will produce incorrect alignment.
- **`borderRadius` clips backgrounds.** Setting `borderRadius` automatically applies `overflow: hidden` to the outer `
`, clipping both `backgroundColor` and `backgroundImage` within the rounded corners.
- **Per-side borders null out all other sides.** When using individual side borders, all other sides are set to `"none"` explicitly. Do not rely on inherited or default border values.
- **`maxWidth` does not constrain the outer column.** The outer `
` always fills its parent — only the inner content table is capped. This is by design for Outlook Classic compatibility.
- **`width` is rarely needed.** In practice, a Column inherits its width from the parent Container cell. Set `width` only when placing a Column outside a Container in a context where no parent provides width.
- **`backgroundImage` renders on the outer `
`, not the border table.** This means `borderRadius` clips the background correctly, but the image sits beneath the border visually.