6.0 KiB

OpenTUI Layout System

OpenTUI uses the Yoga layout engine, providing CSS Flexbox-like capabilities for positioning and sizing components in the terminal.

Overview

Key concepts:

  • Flexbox model: Familiar CSS Flexbox properties
  • Yoga engine: Facebook's cross-platform layout engine
  • Terminal units: Dimensions are in character cells (columns x rows)
  • Percentage support: Relative sizing based on parent

Flex Container Properties

flexDirection

Controls the main axis direction:

// Row (default) - children flow horizontally
<box flexDirection="row">
  <text>1</text>
  <text>2</text>
  <text>3</text>
</box>
// Output: 1 2 3

// Column - children flow vertically
<box flexDirection="column">
  <text>1</text>
  <text>2</text>
  <text>3</text>
</box>
// Output:
// 1
// 2
// 3

// Reverse variants
<box flexDirection="row-reverse">...</box>     // 3 2 1
<box flexDirection="column-reverse">...</box>  // Bottom to top

justifyContent

Aligns children along the main axis:

<box flexDirection="row" width={40} justifyContent="flex-start">
  {/* Children at start (left for row) */}
</box>

<box flexDirection="row" width={40} justifyContent="flex-end">
  {/* Children at end (right for row) */}
</box>

<box flexDirection="row" width={40} justifyContent="center">
  {/* Children centered */}
</box>

<box flexDirection="row" width={40} justifyContent="space-between">
  {/* First at start, last at end, rest evenly distributed */}
</box>

<box flexDirection="row" width={40} justifyContent="space-around">
  {/* Equal space around each child */}
</box>

<box flexDirection="row" width={40} justifyContent="space-evenly">
  {/* Equal space between all children and edges */}
</box>

alignItems

Aligns children along the cross axis:

<box flexDirection="row" height={10} alignItems="flex-start">
  {/* Children at top */}
</box>

<box flexDirection="row" height={10} alignItems="flex-end">
  {/* Children at bottom */}
</box>

<box flexDirection="row" height={10} alignItems="center">
  {/* Children vertically centered */}
</box>

<box flexDirection="row" height={10} alignItems="stretch">
  {/* Children stretch to fill height */}
</box>

<box flexDirection="row" height={10} alignItems="baseline">
  {/* Children aligned by text baseline */}
</box>

flexWrap

Controls whether children wrap to new lines:

<box flexDirection="row" flexWrap="nowrap" width={20}>
  {/* Children overflow (default) */}
</box>

<box flexDirection="row" flexWrap="wrap" width={20}>
  {/* Children wrap to next row */}
</box>

<box flexDirection="row" flexWrap="wrap-reverse" width={20}>
  {/* Children wrap upward */}
</box>

gap

Space between children:

<box flexDirection="row" gap={2}>
  <text>A</text>
  <text>B</text>
  <text>C</text>
</box>
// Output: A  B  C (2 spaces between)

Flex Item Properties

flexGrow

How much a child should grow relative to siblings:

<box flexDirection="row" width={30}>
  <box flexGrow={1}><text>1</text></box>
  <box flexGrow={2}><text>2</text></box>
  <box flexGrow={1}><text>1</text></box>
</box>
// Widths: 7.5 | 15 | 7.5 (1:2:1 ratio)

flexShrink

How much a child should shrink when space is limited:

<box flexDirection="row" width={20}>
  <box width={15} flexShrink={1}><text>Shrinks</text></box>
  <box width={15} flexShrink={0}><text>Fixed</text></box>
</box>

flexBasis

Initial size before growing/shrinking:

<box flexDirection="row">
  <box flexBasis={20} flexGrow={1}>Starts at 20, can grow</box>
  <box flexBasis="50%">Half of parent</box>
</box>

alignSelf

Override parent's alignItems for this child:

<box flexDirection="row" height={10} alignItems="center">
  <text>Centered</text>
  <text alignSelf="flex-start">Top</text>
  <text alignSelf="flex-end">Bottom</text>
</box>

Dimensions

Fixed Dimensions

<box width={40} height={10}>
  {/* Exactly 40 columns by 10 rows */}
</box>

Percentage Dimensions

Parent must have explicit size:

<box width="100%" height="100%">
  <box width="50%" height="50%">
    {/* Half of parent */}
  </box>
</box>

Min/Max Constraints

<box
  minWidth={20}
  maxWidth={60}
  minHeight={5}
  maxHeight={20}
>
  {/* Constrained sizing */}
</box>

Spacing

Padding (inside)

// All sides
<box padding={2}>Content</box>

// Individual sides
<box
  paddingTop={1}
  paddingRight={2}
  paddingBottom={1}
  paddingLeft={2}
>
  Content
</box>

Margin (outside)

// All sides
<box margin={1}>Content</box>

// Individual sides
<box
  marginTop={1}
  marginRight={2}
  marginBottom={1}
  marginLeft={2}
>
  Content
</box>

Positioning

Relative (default)

Element flows in normal document order:

<box position="relative">
  {/* Normal flow */}
</box>

Absolute

Element positioned relative to nearest positioned ancestor:

<box position="relative" width="100%" height="100%">
  <box
    position="absolute"
    left={10}
    top={5}
    width={20}
    height={5}
  >
    Positioned at (10, 5)
  </box>
</box>

Position Properties

<box
  position="absolute"
  left={10}      // From left edge
  top={5}        // From top edge
  right={10}     // From right edge
  bottom={5}     // From bottom edge
>
  Content
</box>

Display

Visibility Control

// Visible (default)
<box display="flex">Visible</box>

// Hidden (removed from layout)
<box display="none">Hidden</box>

Overflow

<box overflow="visible">
  {/* Content can extend beyond bounds (default) */}
</box>

<box overflow="hidden">
  {/* Content clipped at bounds */}
</box>

<box overflow="scroll">
  {/* Scrollable when content exceeds bounds */}
</box>

Z-Index

Control stacking order for overlapping elements:

<box position="relative">
  <box position="absolute" zIndex={1}>Behind</box>
  <box position="absolute" zIndex={2}>In front</box>
</box>

See Also