# Container Component — LLM Reference The `Container` is the **primary layout primitive** in this email builder. It renders as a nested HTML table structure (required for email client compatibility) and controls how child components are **arranged side-by-side (horizontally)** or stacked. A Container is always a direct child of a Section — it cannot be nested inside another Container, directly or indirectly. --- ## Core Concepts ### Horizontal Layout & Width Distribution By default, a Container acts as a horizontal row. The `childrenConstraints` property defines how the available horizontal width is shared among all child elements within that row. ### Width Types A Container is either **full-width** (stretches to its parent) or **fixed-width** (capped at a pixel value, centered by default). | `widthType` | Behavior | | --- | --- | | `"full"` | Fills the available width of the parent | | `"fixed"` | Constrained to `config.width` (e.g. `"600px"`), centered | ### Children Width Distribution When a Container has multiple children, `childrenConstraints.widthDistributionType` controls how horizontal space is split between them. | `widthDistributionType` | Description | | --- | --- | | `"equals"` | Horizontal space is divided equally among all children. | | `"ratio"` | One "main" child gets a fractional share of the horizontal width; remaining children split the rest equally. | | `"manual"` | You specify each child's exact horizontal width as a `px` or `rem` string. | Gap space (if `config.gap` is set) is subtracted from the total horizontal width before distributing widths to children. --- ## ComponentNode JSON Structure ```json { "id": "unique-string-id", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" }, "padding": "24px", "gap": "16px", "backgroundColor": "#ffffff", "borderRadius": "8px", "border": { "width": "1px", "style": "solid", "color": "#e5e7eb" }, "alignItems": "center", "justifyContent": "center", "shouldWrap": true }, "children": [] } ``` --- ## `ContainerConfig` — Full Property Reference ### Required | Property | Type | Description | | --- | --- | --- | | `widthType` | `"full" | "fixed"` | Whether the container fills its parent or is fixed-width | | `childrenConstraints` | `ChildrenConstraints` | How horizontal width is shared among children. **Default:** `{ "widthDistributionType": "equals" }` | ### Layout & Sizing | Property | Type | Example | Description | | --- | --- | --- | --- | | `width` | `string` | `"600px"` | Total horizontal width when `widthType` is `"fixed"` | | `height` | `string` | `"200px"` | Fixed height for the content table | | `padding` | `string` | `"16px 24px"` | Inner padding (CSS shorthand) | | `gap` | `string` | `"12px"` | Horizontal space between side-by-side children | | `shouldWrap` | `boolean` | `true` | When `true`, horizontal children stack vertically on mobile | | `alignItems` | `"start" | "center" | "end"` | `"center"` | Vertical alignment of children within the row | | `justifyContent` | `"start" | "center" | "end"` | `"center"` | Horizontal alignment of the container itself | ### Visual | Property | Type | Example | Description | | --- | --- | --- | --- | | `backgroundColor` | `string` | `"#f9fafb"` | Background fill color | | `borderRadius` | `string` | `"8px"` | Rounds all corners | | `border` | `BorderConfig` | See below | Outer border (full or per-side) | | `backgroundImage` | `object` | See below | Background image settings | ### `BorderConfig` Specify either a **full border** (applies to all sides) or **individual sides**. Do not mix both. ```json // Full border (all sides) "border": { "width": "1px", "style": "solid", "color": "#d1d5db" } // Per-side border "border": { "bottom": { "width": "2px", "style": "solid", "color": "#6366f1" } } ``` Supported side keys: `"top"`, `"right"`, `"bottom"`, `"left"`. Each side object requires `width`, `style`, and `color`. ### `backgroundImage` ```json "backgroundImage": { "src": "https://example.com/hero.jpg", "repeat": "no-repeat", "size": "cover", "position": "center center" } ``` | Property | Type | Options | |---|---|---| | `src` | `string` | Absolute URL | | `repeat` | `string` | `"no-repeat"`, `"repeat"`, `"repeat-x"`, `"repeat-y"` | | `size` | `string` | `"auto"`, `"cover"`, `"contain"` | | `position` | `string` | Any valid CSS `background-position` value | --- ## `ChildrenConstraints` — All Variants ### `"equals"` — Equal horizontal split ```json "childrenConstraints": { "widthDistributionType": "equals" } ``` All children receive identical horizontal width. For a 600px container with 2 children and no gap, each child is 300px wide. --- ### `"ratio"` — Proportional horizontal split ```json "childrenConstraints": { "widthDistributionType": "ratio", "ratio": { "mainChildIndex": 0, "value": [2, 3] } } ``` | Property | Type | Description | | --- | --- | --- | | `mainChildIndex` | `number` | Index of the child receiving the specific fractional share of the row | | `value` | `[number, number]` | `[numerator, denominator]` — e.g. `[2, 3]` means 2/3 of the row width | The remaining 1/3 of the row is split equally among all other children. --- ### `"manual"` — Explicit horizontal widths ```json "childrenConstraints": { "widthDistributionType": "manual", "widths": ["200px", "400px"] } ``` The `widths` array must have exactly the same length as the `children` array. Only `px` and `rem` units are accepted to define the horizontal footprint of each child. --- ## Data Bindings Containers support the `bindings` property for dynamic data. ```json "bindings": { "dataList": "products", "itemAlias": "product", "visible": "user.isPremium === true", "propertyMap": { "config.backgroundColor": "product.brandColor" } } ``` | Property | Description | |---|---| | `dataList` | Dot-path to an array in the Data Layer — makes this component a repeater | | `itemAlias` | Name to reference each item inside children (e.g. `"product"` → `"product.title"`) | | `visible` | JS expression evaluated against the Data Layer; hides the component when falsy | | `propertyMap` | Maps component property paths (prefixed with `config.`) to Data Layer paths | --- ## React Usage ```tsx import Container, { ContainerConfig } from './Container'; const config: ContainerConfig = { widthType: 'fixed', width: '600px', childrenConstraints: { widthDistributionType: 'equals' }, padding: '24px', gap: '16px', backgroundColor: '#ffffff', borderRadius: '8px', }; ``` The component is memoized via `arePropsEqual`. Pass stable `config` references (e.g. with `useMemo`) to avoid unnecessary re-renders. --- ## Common Patterns & Examples ### 1. Full-width section wrapper ```json { "id": "cnt-section-hero", "type": "ContainerComponent", "config": { "widthType": "full", "childrenConstraints": { "widthDistributionType": "equals" }, "backgroundColor": "#1e1b4b", "padding": "48px 24px" }, "children": [{ "id": "hero-text", "type": "TextComponent", "config": { "text": "Hello!" } }] } ``` --- ### 2. Fixed-width centered card ```json { "id": "card-container", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "560px", "childrenConstraints": { "widthDistributionType": "equals" }, "justifyContent": "center", "padding": "32px", "backgroundColor": "#ffffff", "borderRadius": "12px", "border": { "width": "1px", "style": "solid", "color": "#e5e7eb" } }, "children": [] } ``` --- ### 3. Two-column layout (text + image), 2:1 ratio ```json { "id": "two-col", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "ratio", "ratio": { "mainChildIndex": 0, "value": [2, 3] } }, "gap": "24px", "padding": "24px", "shouldWrap": true, "alignItems": "center" }, "children": [ { "id": "text-col", "type": "TextComponent", "config": { "text": "Body copy here" } }, { "id": "image-col", "type": "ImageComponent", "config": { "src": "https://..." } } ] } ``` --- ### 4. Three-column equal layout ```json { "id": "three-col", "type": "ContainerComponent", "config": { "widthType": "fixed", "width": "600px", "childrenConstraints": { "widthDistributionType": "equals" }, "gap": "12px", "padding": "16px", "shouldWrap": true }, "children": [ { "id": "col-1", "type": "ColumnComponent", "config": { "padding": "0", "gap": "12px" }, "children": [] }, { "id": "col-2", "type": "ColumnComponent", "config": { "padding": "0", "gap": "12px" }, "children": [] }, { "id": "col-3", "type": "ColumnComponent", "config": { "padding": "0", "gap": "12px" }, "children": [] } ] } ``` --- ### 5. Hero section with background image ```json { "id": "hero-bg", "type": "ContainerComponent", "config": { "widthType": "full", "childrenConstraints": { "widthDistributionType": "equals" }, "justifyContent": "center", "alignItems": "center", "height": "300px", "padding": "40px", "backgroundImage": { "src": "https://example.com/hero-bg.jpg", "repeat": "no-repeat", "size": "cover", "position": "center center" }, "backgroundColor": "#000000" }, "children": [] } ``` --- ### 6. Repeating product list via data binding ```json { "id": "cnt-product-row", "type": "ContainerComponent", "bindings": { "dataList": "products", "itemAlias": "product" }, "config": { "widthType": "full", "childrenConstraints": { "widthDistributionType": "equals" }, "padding": "12px", "gap": "16px", "backgroundColor": "#f3f4f6" }, "children": [ { "id": "cnt-product-name", "type": "TextComponent", "bindings": { "propertyMap": { "config.text": "product.name" } }, "config": { "text": "Fallback name" } } ] } ``` --- ## Rules & Constraints - **No nesting:** A `Container` cannot be placed inside another `Container`. Use `Column` or `Row` for nested layouts inside a Container cell. - **Horizontal Gap Math:** `gap` is subtracted from total horizontal width before distributing space. Always account for this when using `"manual"` widths. - **`shouldWrap`:** Only takes effect when there are 2+ children. On mobile, the horizontal row collapses and children stack vertically. - **`"manual"` width logic:** Array length must match children count exactly, or no widths are applied to the row. Only `px` and `rem` units are valid. - **`justifyContent`** aligns the whole container within its parent. Use `alignItems` for vertical alignment of children within the row.