Skip to content

Flexbox Layouts ​

To design structured terminal views that adapt dynamically to varying viewport sizes, use the Flexbox positioning engine.

Activating Flex Layout ​

To lay out children inside a container using flex rules, set the display property of the parent to flex:

css
.row-container {
  display: flex;
  flex-direction: row; /* Layout items side-by-side */
}

Alignment Properties ​

  • flex-direction: Defines the main axis formatting flow:
    • row (default): Stacks child elements horizontally from left to right.
    • column: Stacks child elements vertically from top to bottom.
  • flex-grow: Factors how much free space the element claims along the main axis:
    • flex-grow: 1: Expands the element to fill all available leftover cells.
  • flex-shrink: Factors how much the element shrinks when space is constrained:
    • flex-shrink: 0: Prevents the element from shrinking below its default content boundaries.
css
.sidebar {
  width: 25;
  flex-shrink: 0; /* Keeps sidebar width exactly 25 cells */
}
.main-content {
  flex-grow: 1; /* Claims remaining terminal width */
}

Live Demo ​

A row of boxes laid out with justify-content and align-items:

Fullscreen Demo
cpp
// Copyright 2026 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
//
// Flexbox basics.
//
// A flex row distributing three child components, each its own component with
// bound props.
#include <rtxui/rtxui.hpp>
#include <string>
#include <string_view>

using namespace rtxui;

class Box : public Component<Box> {
 public:
  struct Props {
    std::string text = "Box";
    std::string color = "white";
  } props;

  std::string_view view = R"html(
      {text}

      <style>
        self {
          display: block;
          flex-grow: 1;
          border: tall;
          border-color: {color};
          background-color: rgb(22, 27, 34);
          color: {color};
          padding: 1 2;
        }
      </style>
    )html";

  Box() {
    Bind(props.text);
    Bind(props.color);
  }
};

class LayoutDemo : public Component<LayoutDemo> {
 public:
  std::string_view view = R"html(
      <h1>Flexbox</h1>
      <p>A flex row shares its width among three Box components, each given its text and color as props.</p>

      <div class="row">
        <Box text="Sky" color="rgb(121, 192, 255)"></Box>
        <Box text="Blue" color="rgb(88, 166, 255)"></Box>
        <Box text="Navy" color="rgb(56, 117, 230)"></Box>
      </div>

      <style>
        self {
          display: block;
          padding: 1 2;
          background-color: rgba(13, 17, 23, 0.8);
          color: rgb(230, 237, 243);
        }
        h1 {
          color: rgb(88, 166, 255);
        }
        p {
          color: rgb(139, 148, 158);
        }
        .row {
          display: flex;
          gap: 2;
        }
      </style>
    )html";

  LayoutDemo() { Import<Box>(); }
};

int main() {
  auto app = Ref<LayoutDemo>::New();
  Screen screen(app);
  screen.Loop();
  return 0;
}

Live Demo - Interactive Flex Playground ​

The same properties, driven from the UI. Change flex-direction, justify-content, align-items and the per-item flex-grow/flex-shrink /flex-basis, and watch the boxes redistribute:

Fullscreen Demo
cpp
// Copyright 2026 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
//
// An interactive flexbox playground.
//
// Every flex property is driven from the UI: change flex-direction,
// justify-content, align-items, and each item's grow/shrink/basis, and watch
// the boxes redistribute.
#include <rtxui/rtxui.hpp>
#include <string>
#include <string_view>
#include <vector>

using namespace rtxui;

class LayoutFlexDemo : public Component<LayoutFlexDemo> {
 public:
  std::string direction = "row";
  std::string wrap = "wrap";
  std::string justify = "flex-start";
  std::string align = "stretch";
  std::string gap = "0";
  std::string grow = "0";
  std::string shrink = "1";
  std::string basis = "auto";
  int width = 40;
  int height = 12;
  std::vector<std::string> boxes = {"one", "two", "three", "four"};

  void AddBox() {
    const char* names[] = {"one", "two",   "three", "four", "five",
                           "six", "seven", "eight", "nine", "ten"};
    boxes.push_back(names[boxes.size() % 10]);
  }
  void RemoveBox() {
    if (!boxes.empty()) {
      boxes.pop_back();
    }
  }

  std::string_view view = R"html(
      <div class="card">
        <h1>Flexbox playground</h1>
        <p>Each select sets one property: of the container, or of every box in it.</p>

        <div class="split">
          <div class="fields">
          <span>flex-direction</span>
          <select value="{direction}">
            <option value="row">row</option>
            <option value="row-reverse">row-reverse</option>
            <option value="column">column</option>
            <option value="column-reverse">column-reverse</option>
          </select>
          <span>flex-wrap</span>
          <select value="{wrap}">
            <option value="nowrap">nowrap</option>
            <option value="wrap">wrap</option>
            <option value="wrap-reverse">wrap-reverse</option>
          </select>
          <span>justify-content</span>
          <select value="{justify}">
            <option value="flex-start">flex-start</option>
            <option value="center">center</option>
            <option value="flex-end">flex-end</option>
            <option value="space-between">space-between</option>
            <option value="space-around">space-around</option>
            <option value="space-evenly">space-evenly</option>
          </select>
          <span>align-items</span>
          <select value="{align}">
            <option value="stretch">stretch</option>
            <option value="flex-start">flex-start</option>
            <option value="center">center</option>
            <option value="flex-end">flex-end</option>
          </select>
          <span>gap</span>
          <select value="{gap}">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
            <option value="1 2">1 2</option>
          </select>
          <span>flex-grow</span>
          <select value="{grow}">
            <option value="0">0</option>
            <option value="1">1</option>
            <option value="2">2</option>
          </select>
          <span>flex-shrink</span>
          <select value="{shrink}">
            <option value="1">1</option>
            <option value="0">0</option>
            <option value="2">2</option>
          </select>
          <span>flex-basis</span>
          <select value="{basis}">
            <option value="auto">auto</option>
            <option value="0">0</option>
            <option value="10">10</option>
          </select>
          </div>

          <div class="preview">
            <div class="sizes">
              <span>width</span>
              <slider value="{width}" min="10" max="40" width="20" />
              <span>height</span>
              <slider value="{height}" min="3" max="16" width="20" />
            </div>
            <div class="container">
              <for each="{boxes}" as="box">
                <div class="box">{box}</div>
              </for>
            </div>
            <div class="buttons">
              <button onclick="AddBox">Add a box</button>
              <button onclick="RemoveBox">Remove one</button>
            </div>
          </div>
        </div>
      </div>

      <style>
        self {
          --border: rgb(48, 54, 61);
          --muted: rgb(139, 148, 158);
          --accent: rgb(88, 166, 255);

          display: flex;
          align-items: center;
          justify-content: center;
          width: 100%;
          color: rgb(230, 237, 243);
        }
        .card {
          border: tall;
          border-color: var(--border);
          background-color: rgb(22, 27, 34);
          padding: 1 3;
          width: 86;
        }
        h1 {
          color: var(--accent);
        }
        p {
          color: var(--muted);
        }
        .split {
          display: flex;
          gap: 3;
        }
        .fields {
          display: grid;
          grid-template-columns: 17 16;
          row-gap: 1;
          align-content: start;
          flex-shrink: 0;
        }
        .fields span, .sizes span {
          color: var(--muted);
        }
        select:focus, slider:focus {
          color: var(--accent);
        }
        .sizes {
          display: grid;
          grid-template-columns: 8 auto;
        }
        .container {
          display: flex;
          flex-direction: {direction};
          flex-wrap: {wrap};
          justify-content: {justify};
          align-items: {align};
          gap: {gap};
          width: {width};
          height: {height};
          margin: 1 0;
          overflow: hidden;
          border: round;
          border-color: var(--border);
        }
        .box {
          flex-grow: {grow};
          flex-shrink: {shrink};
          flex-basis: {basis};
          border: tall;
          border-color: var(--accent);
          background-color: rgb(22, 45, 77);
          padding: 0 1;
        }
        .buttons {
          display: flex;
          gap: 1;
        }
        button {
          border: tall;
          border-color: var(--border);
          background-color: rgb(13, 17, 23);
          padding: 0 1;
        }
        button:hover, button:focus {
          border-color: var(--accent);
          color: var(--accent);
        }
      </style>
    )html";

  LayoutFlexDemo() {
    Bind(direction);
    Bind(wrap);
    Bind(justify);
    Bind(align);
    Bind(gap);
    Bind(grow);
    Bind(shrink);
    Bind(basis);
    Bind(width);
    Bind(height);
    Bind(boxes);
    Bind(AddBox);
    Bind(RemoveBox);
  }
};

int main() {
  auto app = Ref<LayoutFlexDemo>::New();
  Screen screen(app);
  screen.Loop();
  return 0;
}