Skip to content

Layout

Containers are if blocks. Everything declared inside the block is a child.

if kiln.column(.LG, max_width = 1180) {
kiln.text("Übersicht", .Headline)
if kiln.grid(220) {
for s in m.stats {
if kiln.card() {kiln.stat(s.label, s.value)}
}
}
}
containerwhat
columnchildren top to bottom, fills the width
rowchildren left to right, vertically centered
centerfills the space, centers both ways
card(title)bordered and raised, optional title
scroll()scrolls vertically, fills the space
collapsible(title)section with a header that opens and closes
list_item(selected)clickable row, ask clicked() after it
grid(min_width)equal columns
adaptive(min_width)row when wide, column when narrow
flow()wraps children into lines (chips, badges, tags)
field(label, help, error)a form row with label
actions()buttons at the end, e.g. dialog footers

Inside them: spacer() pushes the following children to the end, separator() draws a line.

kiln.screen() is .Compact, .Medium or .Expanded (breakpoints in the theme) and kiln.by_screen(a, b, c) picks a value for it:

if kiln.scroll(padding = kiln.by_screen(kiln.Space.MD, .LG, .XL)) { ... }

The containers adapt to the space they actually get, not just the window:

containeradapts by
grid(min_width)as many equal columns as fit, rows balanced
adaptive(min_width)row when wide, column with full-width children when narrow
field(label)label beside the control, or above it
actions()right-aligned buttons, stacked full width on phones
tablehides columns by priority when narrow
dialogcentered, or a sheet at the bottom on phones
bar_chartthins out its labels

Ctrl +/−/0 zooms, which also moves the app between screen classes.

A row while it is at least min_width units wide, otherwise a column. When stacked, child containers fill the width even if they have a fixed width:

if kiln.adaptive(720) {
if kiln.column(fill = .Width) { ... } // main content
if kiln.column(width = 280) { ... } // side panel, full width when stacked
}

stacked() tells you whether the innermost adaptive is a column right now.

Every container declared directly inside becomes a cell. Cells in a row share its height. The rows are balanced: 4 cells where 3 columns fit give 2 x 2, not 3 + 1.

if kiln.field("E-Mail", error = valid(m.email) ? "" : "Keine gültige Adresse") {
if t, ok := kiln.text_field(m.email, "name@example.com"); ok {append(out, Set_Email{t})}
}

A non-empty error replaces the help text and gives the text fields, selects and date fields in the block a danger border.