Wireframe
Wireframe widgets mock up a UI — windows, panels, inputs, controls — as diagram shapes. Each wf_* block extends SvgBlock, so it lives inside a diagram: you place it with x / y (or anchors), connect widgets with edges, and mix them with any other shape. Container widgets nest other widgets, so you compose a window of panels of rows of controls; the whole group is sized by its content and the diagram just frames it. They're visual mockups — static SVG, not interactive.
Here's a full window composed of a panel and a button row, framed by a diagram:
diagram {
width = 300 height = 200
wf_window "Account settings" {
wf_panel { title = "Profile"
wf_input "Display name" { value = "Wil Taylor" }
wf_input "Email" { value = "ai@wiltaylor.dev" }
}
wf_row {
wf_button "Cancel"
wf_button "Save" { icon = "lucide.check" }
}
}
}
Placing and connecting widgets
Because widgets are diagram shapes, you place them by x / y and draw edges between them by id — just like connecting any two shapes. A widget is sized by its content, so you only position the top-left corner.
diagram {
width = 360 height = 170
wf_button "Open settings" { id = launch x = 20.0 y = 65.0 }
wf_window "Settings" {
id = win x = 180.0 y = 20.0
wf_checkbox "Dark mode" { checked = true }
wf_button "Close"
}
launch -> win
}
Under an auto-layout diagram (layout = :layered / :force), widgets are sized by their measured content and placed by the solver — omit x / y and let the layout flow them.
Containers
Every container takes @children(Widget) — drop any other widget inside, nested arbitrarily. The Rust renderer measures and lays the children out internally (their x / y are ignored; only the root widget's placement positions the whole group).
wf_window
The outer chrome: a titlebar (with traffic-light controls, hidden by controls = false) over a body that hosts other widgets.
diagram {
width = 300 height = 110
wf_window "Settings" {
wf_label "The window body stacks its children vertically."
}
}
wf_panel
A bordered group with an optional title caption — use it to box a set of related controls.
diagram { width = 220 height = 120
wf_panel { title = "Network"
wf_toggle "Wi-Fi" { on = true }
wf_toggle "Bluetooth"
}
}
wf_row
Lay children out horizontally (a panel / window body stacks vertically by default).
diagram { width = 320 height = 50
wf_row {
wf_button "Back"
wf_button "Next"
wf_button "Finish" { icon = "lucide.check" }
}
}
wf_column
Stack children vertically — the default flow, useful for an explicit column inside a wf_row or wf_grid.
diagram { width = 220 height = 80
wf_column {
wf_label "Name"
wf_input "Full name"
}
}
wf_grid
A grid of equal-width columns; columns sets the count and children flow across the rows.
diagram { width = 280 height = 120
wf_grid { columns = 3
wf_button "1"
wf_button "2"
wf_button "3"
wf_button "4"
wf_button "5"
wf_button "6"
}
}
Controls
wf_label
A plain text label.
diagram { width = 220 height = 30
wf_label "Just some label text."
}
wf_button
A button caption, with an optional leading icon (any pack.name, e.g. "lucide.check").
diagram { width = 320 height = 50
wf_row {
wf_button "Save" { icon = "lucide.check" }
wf_button "Cancel"
wf_button "Delete" { disabled = true }
}
}
wf_input
A text field. With no value the @inline placeholder shows greyed; a value fills it with solid text.
diagram { width = 240 height = 90
wf_column {
wf_input "Search projects…"
wf_input "Name" { value = "Ada Lovelace" }
}
}
wf_dropdown
A select field showing the currently-chosen option label with a chevron.
diagram { width = 200 height = 44
wf_dropdown "Release build"
}
wf_checkbox
An on/off checkbox; checked = true fills the box with a tick.
diagram { width = 240 height = 70
wf_column {
wf_checkbox "Enable telemetry" { checked = true }
wf_checkbox "Join the beta"
}
}
wf_radio
A radio button — like a checkbox but round; mark the active one with selected = true in a group you lay out yourself.
diagram { width = 160 height = 70
wf_column {
wf_radio "Dark" { selected = true }
wf_radio "Light"
}
}
wf_toggle
A sliding on/off switch with an optional trailing label; on = true slides the knob across.
diagram { width = 220 height = 70
wf_column {
wf_toggle "Notifications" { on = true }
wf_toggle "Do not disturb"
}
}
Common fields
Every widget extends a shared Widget interface — its diagram placement geometry (x / y / anchors / connect_points) plus the per-element theming hints:
Custom widgets
Wireframe widgets are user-extensible diagram shapes. Declare a @block("name") type … extends Widget with a lower that returns list<SvgFundamental>, and it plugs into the diagram render path like any custom shape — placed directly in a diagram by its own x / y and connectable by edges. (The built-in containers only lay out the built-in widgets, so a custom widget renders as a standalone shape, not nested inside a wf_window.)
Here's a coloured status wf_badge. The lower reads its x / y and emits a filled box with a centred label — exactly how the built-in process shape lowers — and a fill field recolours an individual instance:
// Extends Widget → a diagram shape. The lower returns SVG fundamentals
// positioned at the widget's own x/y (like the built-in `process`), and a
// `fill` field recolours a single instance.
@block("wf_badge")
type WfBadge extends Widget {
@inline(0) text: utf8
fill = "#2e7d32"
id: identifier? class: list<utf8>? disabled: bool?
x = 0.0 y = 0.0 width = 96.0 height = 26.0
anchor_left: f64? anchor_right: f64? anchor_top: f64? anchor_bottom: f64?
connect_points: list<AnchorSide>?
theme: symbol? accent: symbol? mode: symbol?
lower = fn(b: WfBadge) -> list<SvgFundamental> {
[ SvgFundamental::Rect {
x: b.x, y: b.y, width: b.width, height: b.height,
fill: b.fill, class: b.class,
},
SvgFundamental::Label {
content: b.text,
x: b.x + b.width / 2.0,
y: b.y + b.height / 2.0 + 4.0,
fit_width: b.width, fit_height: b.height,
fill: "#ffffff",
} ]
}
}
diagram {
width = 320 height = 40
wf_badge "passing" { x = 12.0 y = 7.0 }
wf_badge "failing" { x = 130.0 y = 7.0 fill = "#c62828" }
}