Layout System
OpenTUI uses the Yoga layout engine to provide CSS Flexbox-like capabilities for responsive terminal layouts. You can create complex, dynamic interfaces that adapt to terminal size changes.
Flexbox Basics
The layout system supports standard flexbox properties:
import { BoxRenderable, createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
const container = new BoxRenderable(renderer, {
id: "container",
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
width: "100%",
height: 10,
})
const leftPanel = new BoxRenderable(renderer, {
id: "left",
flexGrow: 1,
height: 10,
backgroundColor: "#444",
})
const rightPanel = new BoxRenderable(renderer, {
id: "right",
width: 20,
height: 10,
backgroundColor: "#666",
})
container.add(leftPanel)
container.add(rightPanel)
renderer.root.add(container)
Flex Direction
Control the direction of child elements:
// Vertical layout (default)
{
flexDirection: "column"
}
// Horizontal layout
{
flexDirection: "row"
}
// Reversed directions
{
flexDirection: "row-reverse"
}
{
flexDirection: "column-reverse"
}
Justify Content
Align children along the main axis:
{
justifyContent: "flex-start"
} // Pack at start
{
justifyContent: "flex-end"
} // Pack at end
{
justifyContent: "center"
} // Center children
{
justifyContent: "space-between"
} // Even spacing, no edge gaps
{
justifyContent: "space-around"
} // Even spacing with edge gaps
{
justifyContent: "space-evenly"
} // Truly even spacing
Align Items
Align children along the cross axis:
{
alignItems: "flex-start"
} // Align to start
{
alignItems: "flex-end"
} // Align to end
{
alignItems: "center"
} // Center on cross axis
{
alignItems: "stretch"
} // Stretch to fill (default)
{
alignItems: "baseline"
} // Align baselines
Sizing
Fixed Sizes
{
width: 30, // Fixed width in characters
height: 10, // Fixed height in rows
}
Percentage Sizes
{
width: "100%", // Full width of parent
height: "50%", // Half height of parent
}
Flex Growing and Shrinking
{
flexGrow: 1, // Take up available space
flexShrink: 0, // Don't shrink below content size
flexBasis: 100, // Initial size before flex adjustments
}
Positioning
Relative (Default)
Elements flow normally in the layout:
{
position: "relative",
}
Absolute
Position elements relative to their parent:
{
position: "absolute",
left: 10,
top: 5,
right: 10,
bottom: 5,
}
Padding and Margin
{
// Uniform padding
padding: 2,
// Individual sides
paddingTop: 1,
paddingRight: 2,
paddingBottom: 1,
paddingLeft: 2,
// Margin works the same way
margin: 1,
marginTop: 1,
marginRight: 2,
marginBottom: 1,
marginLeft: 2,
}
Using Constructs
The same layout properties work with the declarative API:
import { Box, Text } from "@opentui/core"
renderer.root.add(
Box(
{
flexDirection: "row",
width: "100%",
height: 10,
},
Box(
{
flexGrow: 1,
backgroundColor: "#333",
padding: 1,
},
Text({ content: "Left Panel" }),
),
Box(
{
width: 20,
backgroundColor: "#555",
padding: 1,
},
Text({ content: "Right Panel" }),
),
),
)
Responsive Layouts
Listen for terminal resize events to create responsive layouts:
const renderer = await createCliRenderer()
renderer.on("resize", (width, height) => {
// Update layout based on new dimensions
if (width < 80) {
container.flexDirection = "column"
} else {
container.flexDirection = "row"
}
})