Skip to main content

Overview

Fern’s layout system provides declarative widgets for arranging UI components. Layouts automatically position children based on alignment, spacing, and flex rules.

Layout Widgets

Row - Horizontal Layout

Arrange widgets horizontally from left to right:
auto row = Fern::Row({
    button1,
    button2,
    button3
}, false, MainAxisAlignment::Center);
auto button1 = Fern::Button(ButtonConfig(0, 0, 80, 40, "OK"));
auto button2 = Fern::Button(ButtonConfig(0, 0, 80, 40, "Cancel"));

auto row = Fern::Row({
    button1,
    button2
});

Fern::addWidget(row);

Column - Vertical Layout

Stack widgets vertically from top to bottom:
auto column = Fern::Column({
    title,
    subtitle,
    content
}, false, MainAxisAlignment::Start);
Example: Form Layout
using namespace Fern;

auto titleText = Text(TextConfig(0, 0, "Login Form")
    .style(TextStyle().fontSize(4).color(Colors::White)));

auto usernameInput = TextInput(/* ... */);
auto passwordInput = TextInput(/* ... */);
auto submitButton = Button(ButtonConfig(0, 0, 200, 40, "Submit"));

auto form = Column({
    titleText,
    SizedBox(0, 20),      // Vertical spacing
    usernameInput,
    SizedBox(0, 10),
    passwordInput,
    SizedBox(0, 20),
    submitButton
}, false, MainAxisAlignment::Start, CrossAxisAlignment::Center);

addWidget(Center(form));

Center - Centering Layout

Center a single widget within available space:
auto centered = Fern::Center(myWidget);
// Center a button on screen
int width = Fern::getWidth();
int height = Fern::getHeight();

auto button = Button(ButtonConfig(0, 0, 120, 40, "Click Me"));
auto centerWidget = std::make_shared<CenterWidget>(0, 0, width, height);
centerWidget->add(button);

addWidget(centerWidget);
Center automatically handles window resizing when implementing ResponsiveWidget.

Padding - Spacing Around Widgets

Add space around widgets:
// Uniform padding (all sides)
auto padded = Fern::Padding(widget, 10);

// Custom padding (left, top, right, bottom)
auto padded = Fern::Padding(widget, 10, 20, 10, 20);
Example: Card Layout
auto content = Column({
    Text(TextConfig(0, 0, "Card Title").style(TextStyle().fontSize(3))),
    SizedBox(0, 10),
    Text(TextConfig(0, 0, "Card content goes here"))
});

auto card = Container(
    Colors::DarkGray,
    100, 100, 300, 200,
    Padding(content, 20)  // 20px padding on all sides
);

Expanded - Flex Spacing

Make widgets expand to fill available space with flex factors:
auto row = Row({
    button1,                    // Fixed size
    Expanded(flexContent, 2),   // Takes 2x space
    Expanded(sidebar, 1)        // Takes 1x space
});
Example: App Layout
using namespace Fern;

int width = getWidth();
int height = getHeight();

// Header (fixed 80px)
auto header = Container(
    Colors::DarkBlue, 0, 0, width, 80,
    Center(Text(Point(0, 0), "HEADER", 2, Colors::White))
);

// Main content (expands to fill)
auto mainContent = Container(
    Colors::Blue, 0, 0, 0, 0,
    Center(Text(Point(0, 0), "Content", 3, Colors::White))
);

// Footer (fixed 60px)
auto footer = Container(
    Colors::DarkGray, 0, 0, 0, 60,
    Center(Text(Point(0, 0), "FOOTER", 2, Colors::White))
);

auto layout = Column({
    header,
    Expanded(mainContent, 1),  // Takes all remaining space
    footer
});

addWidget(layout);

Alignment Options

MainAxisAlignment

Controls alignment along the primary direction (horizontal for Row, vertical for Column):
enum class MainAxisAlignment {
    Start,         // Align to start (left/top)
    Center,        // Center items
    End,           // Align to end (right/bottom)
    SpaceBetween,  // Space evenly, no edge spacing
    SpaceAround,   // Space evenly, half edge spacing
    SpaceEvenly    // Space evenly, equal everywhere
};
Visual Example:
auto row = Row(children, false, MainAxisAlignment::Start);
// [btn1][btn2][btn3]                    |

CrossAxisAlignment

Controls alignment perpendicular to the main axis:
enum class CrossAxisAlignment {
    Start,    // Align to start
    Center,   // Center items
    End,      // Align to end
    Stretch   // Stretch to fill
};
// Vertically center items in a horizontal row
auto row = Row(
    children,
    false,
    MainAxisAlignment::Start,
    CrossAxisAlignment::Center  // Vertical centering
);

SizedBox - Empty Space

Create empty space of specific dimensions:
// Vertical spacing in a column
SizedBox(0, 20)   // 20px height

// Horizontal spacing in a row  
SizedBox(30, 0)   // 30px width

// Fixed size placeholder
SizedBox(100, 100)  // 100x100 square
auto column = Column({
    Text(Point(0, 0), "First", 2, Colors::White),
    SizedBox(0, 15),  // 15px gap
    Text(Point(0, 0), "Second", 2, Colors::White),
    SizedBox(0, 15),
    Text(Point(0, 0), "Third", 2, Colors::White)
});

Complex Layouts

Grid-like Layout with Rows and Columns

using namespace Fern;

// Top row with 3 equal-width boxes
auto topRow = Row({
    Expanded(Container(Colors::Red, 0, 0, 0, 0, 
        Center(Text(Point(0, 0), "1", 3, Colors::White))), 1),
    Expanded(Container(Colors::Green, 0, 0, 0, 0,
        Center(Text(Point(0, 0), "2", 3, Colors::White))), 1),
    Expanded(Container(Colors::Blue, 0, 0, 0, 0,
        Center(Text(Point(0, 0), "3", 3, Colors::White))), 1)
}, false);

// Bottom row with padding
auto bottomRow = Row({
    Expanded(Padding(
        Container(Colors::Yellow, 0, 0, 0, 0,
            Center(Text(Point(0, 0), "4", 3, Colors::Black))
        ), 10), 1)
}, false);

// Main layout
auto layout = Column({
    Expanded(topRow, 1),
    SizedBox(0, 10),
    Expanded(bottomRow, 1)
}, false);

Dashboard Layout

int width = Fern::getWidth();
int height = Fern::getHeight();

// Sidebar (fixed 200px)
auto sidebar = Container(
    Colors::DarkGray, 0, 0, 200, height,
    Padding(
        Column({
            Text(Point(0, 0), "Menu", 3, Colors::White),
            SizedBox(0, 20),
            Button(ButtonConfig(0, 0, 160, 35, "Home")),
            SizedBox(0, 10),
            Button(ButtonConfig(0, 0, 160, 35, "Settings"))
        }),
        20
    )
);

// Main content area (expands)
auto content = Container(
    Colors::LightGray, 0, 0, 0, 0,
    Center(Text(Point(0, 0), "Dashboard", 4, Colors::Black))
);

auto dashboard = Row({
    sidebar,
    Expanded(content, 1)
}, false);

Nested Layouts

Layouts can be nested for complex arrangements:
auto header = Container(
    Colors::DarkBlue, 0, 0, width, 80,
    Row({
        Padding(Text(Point(0, 0), "Logo", 3, Colors::White), 20),
        Expanded(SizedBox(0, 0), 1),  // Spacer
        Button(ButtonConfig(0, 0, 80, 35, "Login")),
        SizedBox(20, 0)
    }, false, MainAxisAlignment::Start, CrossAxisAlignment::Center)
);

auto mainLayout = Column({
    header,
    Expanded(
        Row({
            sidebar,
            Expanded(content, 1)
        }, false),
        1
    ),
    footer
}, false);
Use false as the second parameter to layout factory functions to prevent automatic addition to the widget manager when nesting layouts.

Responsive Layouts

Layouts automatically adjust to window size:
Fern::setWindowResizeCallback([](int newWidth, int newHeight) {
    Fern::WidgetManager::getInstance().handleWindowResize(newWidth, newHeight);
});
Center widgets automatically reposition on resize:
class MyApp {
    std::shared_ptr<CenterWidget> centerWidget;
    
    void setupUI() {
        auto content = Column({/* ... */});
        centerWidget = std::make_shared<CenterWidget>(
            0, 0, getWidth(), getHeight()
        );
        centerWidget->add(content);
        addWidget(centerWidget);
    }
};

Best Practices

1
Use Semantic Layouts
2
Choose layouts that match your intent:
3
  • Row for horizontal toolbars, button groups
  • Column for forms, vertical lists
  • Center for modals, splash screens
  • Expanded for responsive sections
  • 4
    Control Spacing
    5
    Use SizedBox for explicit spacing instead of hardcoded positions:
    6
    // Good
    Column({ widget1, SizedBox(0, 20), widget2 })
    
    // Avoid
    widget2->setPosition(x, y + 20);
    
    7
    Leverage Alignment
    8
    Use alignment enums instead of manual positioning:
    9
    // Good
    Row(children, false, MainAxisAlignment::SpaceBetween)
    
    // Avoid calculating positions manually
    
    10
    Nest Thoughtfully
    11
    Limit nesting depth for better performance and maintainability.

    Next Steps

    Build docs developers (and LLMs) love