> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/anomalyco/opentui/llms.txt
> Use this file to discover all available pages before exploring further.

# Layout System

> Yoga flexbox layout engine for responsive, flexible terminal UI layouts

## Overview

OpenTUI uses the **Yoga** layout engine, which implements a subset of CSS Flexbox. This provides:

* Responsive layouts that adapt to terminal size
* Flexible sizing with grow/shrink behavior
* Alignment and justification controls
* Row and column layouts
* Nested layout containers

Yoga was created by Facebook (now Meta) and is the same layout engine used in React Native.

<Info>
  Yoga is implemented in native code (Zig) for high performance, but you interact with it through TypeScript.
</Info>

## Flexbox Basics

### Flex Direction

Control whether children stack horizontally or vertically:

```typescript theme={null}
import { GroupRenderable } from "@opentui/core"

const row = new GroupRenderable(renderer, {
  flexDirection: "row",        // Horizontal layout →
  // or "column" (default)     // Vertical layout ↓
  // or "row-reverse"          // Reverse horizontal ←
  // or "column-reverse"       // Reverse vertical ↑
})
```

### Justify Content

Align children along the **main axis** (direction of flex flow):

```typescript theme={null}
const container = new GroupRenderable(renderer, {
  flexDirection: "row",
  justifyContent: "space-between",
  // Options:
  // "flex-start"    - Pack at start (default)
  // "flex-end"      - Pack at end
  // "center"        - Center items
  // "space-between" - Space between items
  // "space-around"  - Space around items
  // "space-evenly"  - Equal spacing
})
```

### Align Items

Align children along the **cross axis** (perpendicular to flex flow):

```typescript theme={null}
const container = new GroupRenderable(renderer, {
  flexDirection: "row",
  alignItems: "center",
  // Options:
  // "flex-start"  - Align to start (default)
  // "flex-end"    - Align to end
  // "center"      - Center items
  // "baseline"    - Align baselines
  // "stretch"     - Stretch to fill
})
```

### Align Self

Override `alignItems` for a specific child:

```typescript theme={null}
const child = new BoxRenderable(renderer, {
  alignSelf: "flex-end",  // This child aligns to end, others follow parent
})
```

## Sizing

### Fixed Sizes

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  width: 50,   // Fixed width: 50 cells
  height: 20,  // Fixed height: 20 cells
})
```

### Auto Sizing

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  width: "auto",   // Size to fit content
  height: "auto",
})
```

### Percentage Sizing

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  width: "50%",   // 50% of parent width
  height: "25%",  // 25% of parent height
})
```

### Min/Max Constraints

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  minWidth: 20,
  maxWidth: 100,
  minHeight: 10,
  maxHeight: "50%",
})
```

## Flex Properties

### Flex Grow

Control how much a child grows to fill available space:

```typescript theme={null}
const sidebar = new BoxRenderable(renderer, {
  width: 20,      // Fixed width
  flexGrow: 0,    // Don't grow (default)
})

const content = new BoxRenderable(renderer, {
  flexGrow: 1,    // Grow to fill remaining space
})
```

Multiple children with `flexGrow` share space proportionally:

```typescript theme={null}
const left = new BoxRenderable(renderer, {
  flexGrow: 1,    // Gets 1/3 of available space
})

const center = new BoxRenderable(renderer, {
  flexGrow: 2,    // Gets 2/3 of available space
})

const right = new BoxRenderable(renderer, {
  flexGrow: 1,    // Gets 1/3 of available space
})
```

### Flex Shrink

Control how much a child shrinks when space is limited:

```typescript theme={null}
const important = new BoxRenderable(renderer, {
  width: 50,
  flexShrink: 0,  // Never shrink below 50
})

const flexible = new BoxRenderable(renderer, {
  width: 50,
  flexShrink: 1,  // Can shrink if needed (default)
})
```

<Info>
  By default, elements with explicit width/height have `flexShrink: 0`, while auto-sized elements have `flexShrink: 1`.
</Info>

### Flex Basis

Set the initial size before growing/shrinking:

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  flexBasis: 30,     // Start at 30 cells
  flexGrow: 1,       // Then grow to fill space
})
```

### Flex Wrap

Control whether children wrap to new lines:

```typescript theme={null}
const container = new GroupRenderable(renderer, {
  flexDirection: "row",
  flexWrap: "wrap",
  // Options:
  // "nowrap" - Single line (default)
  // "wrap"   - Wrap to new lines
  // "wrap-reverse" - Wrap in reverse
})
```

## Spacing

### Margin

Add space outside an element:

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  margin: 2,           // All sides
  marginX: 3,          // Horizontal (left + right)
  marginY: 1,          // Vertical (top + bottom)
  marginTop: 1,        // Individual sides
  marginRight: 2,
  marginBottom: 1,
  marginLeft: 2,
})
```

Margins support:

* Fixed numbers: `margin: 5`
* Auto centering: `marginLeft: "auto"`
* Percentages: `margin: "10%"`

### Padding

Add space inside an element:

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  padding: 2,          // All sides
  paddingX: 3,         // Horizontal
  paddingY: 1,         // Vertical
  paddingTop: 1,       // Individual sides
  paddingRight: 2,
  paddingBottom: 1,
  paddingLeft: 2,
})
```

Padding supports:

* Fixed numbers: `padding: 5`
* Percentages: `padding: "5%"`

## Common Layouts

### Horizontal Split

Two columns with fixed sidebar:

```typescript theme={null}
import { GroupRenderable, BoxRenderable } from "@opentui/core"

const container = new GroupRenderable(renderer, {
  flexDirection: "row",
  width: "100%",
  height: "100%",
})

const sidebar = new BoxRenderable(renderer, {
  width: 20,          // Fixed width
  backgroundColor: "#333",
})

const content = new BoxRenderable(renderer, {
  flexGrow: 1,        // Fill remaining space
  backgroundColor: "#111",
})

container.add(sidebar)
container.add(content)
```

### Vertical Split

Header, content, footer:

```typescript theme={null}
const container = new GroupRenderable(renderer, {
  flexDirection: "column",
  width: "100%",
  height: "100%",
})

const header = new BoxRenderable(renderer, {
  height: 3,          // Fixed height
  backgroundColor: "#444",
})

const content = new BoxRenderable(renderer, {
  flexGrow: 1,        // Fill remaining space
  backgroundColor: "#111",
})

const footer = new BoxRenderable(renderer, {
  height: 1,          // Fixed height
  backgroundColor: "#444",
})

container.add(header)
container.add(content)
container.add(footer)
```

### Centered Content

```typescript theme={null}
const container = new GroupRenderable(renderer, {
  width: "100%",
  height: "100%",
  justifyContent: "center",  // Center vertically (column direction)
  alignItems: "center",      // Center horizontally
})

const dialog = new BoxRenderable(renderer, {
  width: 40,
  height: 15,
  border: true,
})

container.add(dialog)
```

### Space Between

Evenly distribute children:

```typescript theme={null}
const toolbar = new GroupRenderable(renderer, {
  flexDirection: "row",
  justifyContent: "space-between",
  width: "100%",
})

toolbar.add(new TextRenderable(renderer, { content: "File" }))
toolbar.add(new TextRenderable(renderer, { content: "Edit" }))
toolbar.add(new TextRenderable(renderer, { content: "View" }))
// Items will be evenly spaced: File <---> Edit <---> View
```

### Responsive Grid

```typescript theme={null}
const grid = new GroupRenderable(renderer, {
  flexDirection: "row",
  flexWrap: "wrap",
  width: "100%",
})

for (let i = 0; i < 12; i++) {
  grid.add(new BoxRenderable(renderer, {
    width: "25%",  // 4 columns
    height: 5,
    margin: 1,
  }))
}
```

## Position Types

### Relative Positioning

Default - element participates in flexbox layout:

```typescript theme={null}
const box = new BoxRenderable(renderer, {
  position: "relative",  // Default
})
```

### Absolute Positioning

Remove element from flex flow and position manually:

```typescript theme={null}
const overlay = new BoxRenderable(renderer, {
  position: "absolute",
  top: 0,
  right: 0,
  width: 30,
  height: 10,
  zIndex: 100,  // Render on top
})
```

Absolute positioning:

* Doesn't affect sibling layout
* Positioned relative to parent
* Requires explicit size and position

## Overflow

Control how content beyond bounds is handled:

```typescript theme={null}
const scrollable = new BoxRenderable(renderer, {
  overflow: "scroll",   // Enable scrolling (clips + allows scroll)
  // or "hidden"        // Clip content
  // or "visible"       // Show all content (default)
  width: 50,
  height: 20,
})
```

When `overflow: "scroll"` or `overflow: "hidden"`, children are clipped to the parent's bounds.

## Dynamic Layout Updates

Layout is automatically recalculated when:

* Children are added/removed
* Size properties change
* Flex properties change
* Terminal is resized

```typescript theme={null}
// This triggers layout recalculation
box.width = 100
box.flexGrow = 1
container.add(newChild)
```

Access computed layout after recalculation:

```typescript theme={null}
box.on("resize", () => {
  console.log(`New size: ${box.width}x${box.height}`)
})
```

## Layout Performance

<Tip>
  **Minimize layout thrashing** - Batch property changes when possible rather than updating one at a time.
</Tip>

<Tip>
  **Use absolute positioning sparingly** - Absolute elements still participate in layout calculations but don't affect siblings.
</Tip>

<Info>
  Yoga layout calculation is fast, but deeply nested trees with many children can impact performance. Profile if you notice slowness.
</Info>

## Layout Options Reference

```typescript theme={null}
interface LayoutOptions {
  // Flex container
  flexDirection?: "row" | "column" | "row-reverse" | "column-reverse"
  flexWrap?: "nowrap" | "wrap" | "wrap-reverse"
  justifyContent?: "flex-start" | "flex-end" | "center" | "space-between" | "space-around" | "space-evenly"
  alignItems?: "flex-start" | "flex-end" | "center" | "baseline" | "stretch"

  // Flex child
  flexGrow?: number
  flexShrink?: number
  flexBasis?: number | "auto"
  alignSelf?: "auto" | "flex-start" | "flex-end" | "center" | "baseline" | "stretch"

  // Position
  position?: "relative" | "absolute"
  top?: number | "auto" | `${number}%`
  right?: number | "auto" | `${number}%`
  bottom?: number | "auto" | `${number}%`
  left?: number | "auto" | `${number}%`

  // Size
  width?: number | "auto" | `${number}%`
  height?: number | "auto" | `${number}%`
  minWidth?: number | `${number}%`
  minHeight?: number | `${number}%`
  maxWidth?: number | `${number}%`
  maxHeight?: number | `${number}%`

  // Spacing
  margin?: number | "auto" | `${number}%`
  marginX?: number | "auto" | `${number}%`
  marginY?: number | "auto" | `${number}%`
  marginTop?: number | "auto" | `${number}%`
  marginRight?: number | "auto" | `${number}%`
  marginBottom?: number | "auto" | `${number}%`
  marginLeft?: number | "auto" | `${number}%`

  padding?: number | `${number}%`
  paddingX?: number | `${number}%`
  paddingY?: number | `${number}%`
  paddingTop?: number | `${number}%`
  paddingRight?: number | `${number}%`
  paddingBottom?: number | `${number}%`
  paddingLeft?: number | `${number}%`

  // Overflow
  overflow?: "visible" | "hidden" | "scroll"
}
```
