Leftover space in a container has exactly one policy today: flexible children absorb it. There is no way to say "pack these to the end", "centre them", or "spread them evenly" without inserting spacers by hand.
Today
Constraint (packages/hqtui/src/layout.ts:20) carries size, min, max and intrinsic, and solve() distributes what is left over to fr/fill children. Anything else is manual: the demo's own status row does
r.badge({ text: "err", color: entry.danger, size: 6 });
r.spacer("fill");
to push content left, and the dashboard uses p.spacer("fill") to bottom-align a divider. That works, but it is layout state encoded as a sibling, and it does not survive someone reordering the children.
What ratatui does
Flex::{Legacy, Start, End, Center, SpaceBetween, SpaceEvenly, SpaceAround} on the layout, orthogonal to the constraints themselves.
https://docs.rs/ratatui/latest/ratatui/layout/enum.Flex.html
Proposal
Add justify to ContainerOptions:
ui.row({ justify: "space-between" }, r => { ... });
with "start" | "end" | "center" | "space-between" | "space-around" | "space-evenly", defaulting to "start" so every existing layout renders unchanged. It applies only when the children leave slack — a row containing any fr/fill child has none, so the option is inert there and costs nothing.
The whole change is inside solve() plus one option passed through Container. Existing spacer("fill") code keeps working.
Cost
Rendering behaviour, so it lands in all six ports (ports/{rust,go,python,zig,cpp} and the COBOL adapter) with regenerated conformance fixtures. The TypeScript side is small; the ports are the work. Default-start means the fixtures should regenerate byte for byte until someone opts in, which makes it a safe one to do early.
Leftover space in a container has exactly one policy today: flexible children absorb it. There is no way to say "pack these to the end", "centre them", or "spread them evenly" without inserting spacers by hand.
Today
Constraint(packages/hqtui/src/layout.ts:20) carriessize,min,maxandintrinsic, andsolve()distributes what is left over tofr/fillchildren. Anything else is manual: the demo's own status row doesto push content left, and the dashboard uses
p.spacer("fill")to bottom-align a divider. That works, but it is layout state encoded as a sibling, and it does not survive someone reordering the children.What ratatui does
Flex::{Legacy, Start, End, Center, SpaceBetween, SpaceEvenly, SpaceAround}on the layout, orthogonal to the constraints themselves.https://docs.rs/ratatui/latest/ratatui/layout/enum.Flex.html
Proposal
Add
justifytoContainerOptions:with
"start" | "end" | "center" | "space-between" | "space-around" | "space-evenly", defaulting to"start"so every existing layout renders unchanged. It applies only when the children leave slack — a row containing anyfr/fillchild has none, so the option is inert there and costs nothing.The whole change is inside
solve()plus one option passed throughContainer. Existingspacer("fill")code keeps working.Cost
Rendering behaviour, so it lands in all six ports (
ports/{rust,go,python,zig,cpp}and the COBOL adapter) with regenerated conformance fixtures. The TypeScript side is small; the ports are the work. Default-startmeans the fixtures should regenerate byte for byte until someone opts in, which makes it a safe one to do early.