Responsive
Continuous Max.X plus Theme breakpoints — reflow by default, stepped structure when you need it.
Every widget lays out from the Max.X it is given this frame — that is
the continuous layer (Wrap, auto-fit
SimpleGrid). For Chakra-style stepped structure
(columns={{ base: 1, md: 2, lg: 4 }}), Theme owns named breakpoints and layout
props resolve against them with a zero-alloc walk.
Resize the browser on the demos below. Apps override breakpoint sizes with
JSON loaded at NewTheme — not registry.json.
The doctrine
Pass the width you have; never invent a fake one. Gio hands every
layout a layout.Constraints. lotusui components honor it. The anti-pattern is
clamping gtx.Constraints.Max.X to a constant “for the demo.”
Two layers: continuous reflow (Wrap, minChildWidth SimpleGrid) and stepped
structure (Theme breakpoints + Cols / Dps / Bools /
Show). Prefer continuous when equal tiles should grow smoothly; use stepped when
column count or visibility must jump at named widths.
Theme breakpoints
Defaults (dp): base=0, sm=480, md=768,
lg=992, xl=1280, 2xl=1536. Mobile-first: each step whose
min ≤ Max.X overrides. Resolve is Theme.BreakpointIndex — O(steps), zero alloc.
Layout structure only (columns, spans, gaps, page max, show/hide) — not every visual prop.
// App-owned JSON (dp mins) — load at startup:
bp, err := lotusui.ParseBreakpointsJSON(jsonBytes)
th := lotusui.NewTheme(lotusui.WithBreakpoints(bp))
// Stepped columns (Chakra object syntax):
lotusui.Grid{
Cols: lotusui.Cols(1).At("md", 2).At("lg", 4),
Gap: th.Space.SM,
}.Layout(th, gtx, items...)
Readable page column
LayoutPage(th, gtx, …) caps content at
th.PageMax (default 920dp) or th.PageMaxAt when set. Inside that
column, children still see the column width.
lotusui.LayoutPage(th, gtx, func(gtx C) D {
return lotusui.VStack(th.Space.MD,
header,
lotusui.SimpleGrid(th, gtx, cards, lotusui.SimpleGridProps{
MinChildWidth: 180, MaxCols: 4, Gap: th.Space.SM,
}, cardCell),
lotusui.Wrap(th.Space.SM, layout.Middle, chips...),
)(gtx)
})
Wrap — flowing chips and labels
Wrap is CSS flex-wrap for Gio: each child
is measured at intrinsic width, then packed left-to-right; when the next child would exceed
Max.X, a new line starts. Prefer it for badges and filter chips.
HStack never wraps.
lotusui.Wrap(th.Space.SM, layout.Middle,
chip("Design"), chip("Engineering"), chip("Product"),
chip("Marketing"), chip("Sales"), chip("Support"),
// …)
SimpleGrid — continuous or stepped
SimpleGrid continuous mode:
columns = min(MaxCols, floor(Max.X / MinChildWidth)). Stepped mode: set
Columns: Cols(1).At("sm", 2).At("lg", 4) and ignore minChildWidth.
lotusui.SimpleGrid(th, gtx, items, lotusui.SimpleGridProps{
MinChildWidth: 140, MaxCols: 4, Gap: th.Space.SM,
}, cell)
// or stepped:
lotusui.SimpleGrid(th, gtx, items, lotusui.SimpleGridProps{
Columns: lotusui.Cols(1).At("sm", 2).At("lg", 4), Gap: th.Space.SM,
}, cell)
Tabs and AnnotatedText
Horizontal Tabs and AnnotatedText use Wrap so labels never squeeze to one character under a narrow Max.X.
tabs := lotusui.Tabs{Options: lotusui.TabOpts(
"Changes", "Staging", "Production", "Reviews", "Approvals", "History",
)}
Show / hide and Dialog width
Show(th, gtx, Bools(false).At("lg", true), w) hides below a step.
Dialog / AlertDialog take Sizes / Widths for stepped card width —
not Button density Size.
lotusui.Show(th, gtx, lotusui.Bools(false).At("lg", true), sidebar)
d.Sizes = lotusui.Sizes(lotusui.SizeSM).At("md", lotusui.SizeLG).At("xl", lotusui.Size2XL)
Panes and scrolling
Split panes each get their own Max.X — put Wrap / SimpleGrid / Tabs inside. Scroll helpers are vertical overflow, not a substitute for horizontal reflow.
s.Layout(gtx, th.Space.MD, depth,
lotusui.SplitBox(th, listPane),
lotusui.SplitBox(th, func(gtx C) D {
return lotusui.Wrap(th.Space.SM, layout.Middle, filters...)(gtx)
}),
)
Choosing the right primitive
| Need | Use | Avoid |
|---|---|---|
| Readable app column | LayoutPage(th, …) | Full-bleed Flexed edge-to-edge |
| Flowing chips / tags | Wrap | HStack (squeezes) |
| Equal tiles, smooth N | SimpleGrid minChildWidth | Hard-coded column Flex |
| Equal tiles, stepped N | SimpleGrid Columns / Grid.Cols | Hand if Max.X trees |
| Explicit spans | Grid | Nested HStacks |
| Hide below a step | Show + Bools | Clamping Max.X to 0 |
| Custom step mins | ParseBreakpointsJSON + WithBreakpoints | Editing registry.json |