LayoutBuilder

LayoutBuilder is the layout-aware counterpart to Builder.
It gives your closure the current BoxConstraints so the output can change with available space. Use it for meaningful responsive structure, such as choosing between a one-column mobile layout and a two-pane desktop layout. Do not use it for every padding or gap change; ordinary composition is usually clearer for small visual adjustments.

Example

use fission::prelude::*;

let responsive = LayoutBuilder::<MyState>::new(|_ctx, _view, constraints| {
    if constraints.max_w > 720.0 {
        Row {
            gap: Some(24.0),
            children: widgets![
                Text::new("Sidebar"),
                Text::new("Main content"),
            ],
            ..Default::default()
        }
        .into()
    } else {
        Column {
            gap: Some(16.0),
            children: widgets![
                Text::new("Main content"),
                Text::new("Sidebar"),
            ],
            ..Default::default()
        }
        .into()
    }
})
.id(WidgetId::explicit("responsive-shell"))
.flex_grow(1.0);

Field table

Field
Type
Meaning
Notes / default behavior
LayoutBuilder::new(...)
Fn(BuildCtxHandle<S>, ViewHandle<S>, BoxConstraints) -> Widget
Creates the responsive closure.
Required. Keep the closure pure and deterministic.
id
Option<WidgetId>
Stable widget identity for reading constraints from the previous layout pass.
Defaults to None. When present, the result is wrapped in a Container with that id.
flex_grow
f32
Extra space the wrapped result can absorb.
Defaults to 0.0. Applied when id is set.
flex_shrink
f32
How much the wrapped result may shrink.
Defaults to 1.0. Applied when id is set.

How constraint lookup works

When id is set, LayoutBuilder reads the constraints recorded for that id during the previous layout pass. If no prior constraints exist yet, it falls back to loose constraints based on the current viewport. This keeps responsive branching deterministic while still letting a component react to real layout information.

Production checklist

For LayoutBuilder, review the fields that change behavior before treating the widget as finished: LayoutBuilder::new(...), id, flex_grow, flex_shrink. The goal is to make the product rule visible in state and actions, not hidden inside ad-hoc construction code.
If this widget appears inside an interactive flow, keep the surrounding action binding in the parent component and test that the flow still has one clear reducer path.
Set id only when identity must be stable across filtering, reordering, diagnostics, or tests; otherwise let Fission derive identity from structure.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Prefer parent layout and design-system sizing first; use explicit size or spacing fields when the product layout requires that constraint on this widget specifically.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same LayoutBuilder setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.
Builder, Row, Column, and SimpleGrid.
Fission
A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.
Copyright (c) 2026 Fission
Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.
Fission 0.7.0