Widget Components & Modifiers
Available components and modifiers for widgets.
Status: this page mixes (a) tiny fragments showing component shape — rendered as plain
textbecause they’re not standalone declarations and can’t compile — and (b) one full verified Widget at the bottom that compile-links viadocs/examples/widgets/snippets.ts. The doc-tests harness can’t drive--target ios-widget/android-widget/watchos-widget/wearos-tiledirectly (each needs--app-bundle-idand a platform SDK — #194). Note also that the modifier parser incrates/perry-hir/src/lower.rs(parse_modifiers_from_args/parse_single_modifier) only reads modifiers from inline option-object arguments — e.g.Text("hi", { font: "title", color: "red" })andVStack([...], { padding: 16 }). Method-style chains likeText("hi").font("title")shown below parse without error but drop the modifier at HIR-lowering time (#195). The chain form is documented here because it reads naturally; the verified Complete Example at the bottom of the page uses the inline-options form that actually round-trips through the widget codegen path. The end-to-end reference isexamples/widget_demo.ts.
Text
Text("Hello, World!")
Text(`${entry.name}: ${entry.value}`)
Text Modifiers
const t = Text("Styled");
t.font("title"); // .title, .headline, .body, .caption, etc.
t.color("blue"); // Named color or hex
t.bold();
Layout
VStack
VStack([
Text("Top"),
Text("Bottom"),
])
HStack
HStack([
Text("Left"),
Spacer(),
Text("Right"),
])
ZStack
ZStack([
Image("background"),
Text("Overlay"),
])
Spacer
Flexible space that expands to fill available room:
HStack([
Text("Left"),
Spacer(),
Text("Right"),
])
Image
Display SF Symbols or asset images:
Image("star.fill") // SF Symbol
Image("cloud.sun.rain.fill") // SF Symbol
ForEach
Iterate over array entry fields to render a list of components:
ForEach(entry.items, (item) =>
HStack([
Text(item.name),
Spacer(),
Text(`${item.value}`),
])
)
Divider
A visual separator line:
VStack([
Text("Above"),
Divider(),
Text("Below"),
])
Label
A label with text and an SF Symbol icon:
Label("Downloads", "arrow.down.circle")
Label(`${entry.count} items`, "folder.fill")
Gauge
A circular or linear progress indicator:
Gauge(entry.progress, 0, 100) // value, min, max
Gauge(entry.battery, 0, 1.0)
Modifiers
Widget components support SwiftUI-style modifiers. The chain forms shown below
parse but drop their modifiers at HIR-lowering time
(#195) — use the inline
option-object form (Text("hi", { font: "title" }),
VStack([...], { padding: 16 })) for the form that actually reaches the
codegen, as in the Complete Example at the bottom of
this page.
Font
Text("Title").font("title")
Text("Body").font("body")
Text("Caption").font("caption")
Color
Text("Red text").color("red")
Text("Custom").color("#FF6600")
Padding
VStack([...]).padding(16)
Frame
widget.frame(width, height)
Max Width
widget.maxWidth("infinity") // Expand to fill available width
Minimum Scale Factor
Allow text to shrink to fit:
Text("Long text").minimumScaleFactor(0.5)
Container Background
Set background color for the widget container:
VStack([...]).containerBackground("blue")
Widget URL
Make the widget tappable with a deep link:
VStack([...]).url("myapp://detail/123")
Edge-Specific Padding
Apply padding to specific edges:
VStack([...]).paddingEdge("top", 8)
VStack([...]).paddingEdge("horizontal", 16)
Conditionals
Render different components based on entry data:
render: (entry) =>
VStack([
entry.isOnline
? Text("Online").color("green")
: Text("Offline").color("red"),
]),
Complete Example
The full Widget below is the verified extract — it compile-links on the host LLVM target and uses the inline-options modifier form that round-trips through the codegen.
Widget({
kind: "StatsWidget",
displayName: "Stats",
description: "Shows daily stats",
entryFields: {
steps: "number",
calories: "number",
distance: "string",
},
// Inline-options modifier form — the `.font("title").bold()` chain form
// parses but its modifiers don't reach the codegen (#195).
render: (entry) =>
VStack([
HStack([
Image("figure.walk"),
Text("Daily Stats", { font: "headline" }),
]),
Spacer(),
HStack([
VStack([
Text(`${entry.steps}`, { font: "title", fontWeight: "bold" }),
Text("steps", { font: "caption", color: "gray" }),
]),
Spacer(),
VStack([
Text(`${entry.calories}`, { font: "title", fontWeight: "bold" }),
Text("cal", { font: "caption", color: "gray" }),
]),
Spacer(),
VStack([
Text(entry.distance, { font: "title", fontWeight: "bold" }),
Text("km", { font: "caption", color: "gray" }),
]),
]),
], { padding: 16 }),
})
Next Steps
- Creating Widgets — Widget() API
- Overview — Widget system overview