row and column
Boxes that flow their children along one axis: a row left to right, a column top to bottom.
They are the main layout tools; everything else is placed inside one. The two accept the same
properties and differ only in their main axis. For children built from data, use a list.
A meter: a "Fill"-wide track with a percentage-wide fill that follows a signal.
local volume = state("volume", 0.45)
local meter = row {
width = "Fill",
height = 6,
radius = 3,
background = "#313244",
children = { rect {
width = volume:map(function(v) return string.format("%d%%", math.floor((v or 0) * 100 + 0.5)) end),
height = "Fill",
radius = 3,
background = "#89B4FA",
animate = { width = 150 },
} },
}
return column { width = 240, children = { meter } }
Properties
row and column take the common and
box properties, plus:
| Property | Type | Default | Behaviour |
|---|---|---|---|
children | Node[]|Bound | None | Array of node tables, up to 10000; a nil or false entry is an error. Laid out in order along the main axis. Bind a signal of an array to switch views |
spacing | number|Bound | 0 | Px between visible children; negative values overlap them. Not range-checked |
scroll | Bound | None | A scroll(name) signal; makes the node a scrolling viewport along its main axis (scroll) |
How the container packs its children:
| Axis | Set by | Effect |
|---|---|---|
Main (row: horizontal, column: vertical) | The container’s own align_h (row) or align_v (column) | "Start", "Center", "End" pack the children; "Stretch" packs like "Start". The children’s own value on this axis is ignored |
| Cross | Each child’s align_v (row) or align_h (column) | Places that child across the row’s height or the column’s width; "Stretch" fills it |
"Fill" children along the main axis share what the others leave, and no child shrinks; see
sizes.
How do I…
| Task | Answer |
|---|---|
| Show a progress bar | The meter above |
| Push items apart | Below |
| Split a bar into three groups | The bar: two "Fill" rows around a content-sized middle |
| Centre items in a row | align_h = "Center" on the row itself |
| Make children equal width | Give each width = "Fill" |
| Scroll overflowing content | Bound the axis (height or max_height on a column), then scroll = scroll("name") (scroll) |
| Overlap items, like stacked avatars | Negative spacing |
Push items apart
A "Fill" child takes the space its siblings leave, so a bare rect makes a spacer:
local header = row {
width = 300,
spacing = 8,
children = {
text { content = "Wi-Fi", font_size = 14, foreground = "#CDD6F4", align_v = "Center" },
rect { width = "Fill" }, -- takes the space left over, pushing what follows to the end
text { content = "Connected", foreground = "#A6ADC8", align_v = "Center" },
},
}
return header
Gotchas
| Trap | Fix |
|---|---|
align_h = "Center" on a child of a row does nothing | The row packs its main axis: set align_h on the row, or use "Fill" spacers |
align_v = "Center" on a row leaves its children at the top | A row’s own align_v places the row in its parent. Set align_v on each child, as in push items apart |
A "Fill" child of a content-sized row is 0 wide | The row has no leftover space to share. Give the row a width or "Fill" |
direction = "Horizontal" on a column is refused | direction is a list property. Use a row |
A scroll row or column never scrolls | Its size on the main axis is content-sized, so nothing overflows. Set width/height or a max_* |
See also: list, rect, layout model.
Source: vocabulary, layout solver, spacing and alignment parsers, scroll.