Example
Support queue
A support queue with the oldest ticket highlighted.
{
"v": 1,
"refresh": 900,
"accessibility": "Twelve open tickets, oldest waiting four hours",
"url": "https://support.example.com/queue",
"view": {
"type": "vstack",
"spacing": 0,
"padding": 16,
"children": [
{
"type": "hstack",
"align": "center",
"spacing": 8,
"children": [
{
"type": "text",
"text": "Open tickets",
"style": "headline",
"color": "primary"
},
{"type": "spacer"},
{
"type": "zstack",
"align": "center",
"children": [
{
"type": "vstack",
"children": [],
"w": 30,
"h": 22,
"corner": 11,
"bg": "red",
"opacity": 0.18
},
{
"type": "text",
"text": "12",
"size": 13,
"weight": "bold",
"color": "red"
}
]
}
]
},
{"type": "spacer", "minLength": 12},
{
"type": "hstack",
"spacing": 10,
"align": "center",
"padding": 9,
"children": [
{
"type": "zstack",
"align": "center",
"children": [
{
"type": "vstack",
"children": [],
"w": 32,
"h": 20,
"corner": 5,
"bg": "red",
"opacity": 0.18
},
{
"type": "text",
"text": "P1",
"size": 11,
"weight": "bold",
"color": "red"
}
]
},
{
"type": "vstack",
"align": "leading",
"spacing": 1,
"w": 210,
"children": [
{
"type": "text",
"text": "Cannot export CSV from the reports page",
"style": "subheadline",
"color": "primary",
"lines": 1
},
{
"type": "text",
"text": "ACME Ltd",
"style": "caption",
"color": "secondary"
}
]
},
{"type": "spacer"}
]
},
{"type": "divider"},
{
"type": "hstack",
"spacing": 10,
"align": "center",
"padding": 9,
"children": [
{
"type": "zstack",
"align": "center",
"children": [
{
"type": "vstack",
"children": [],
"w": 32,
"h": 20,
"corner": 5,
"bg": "orange",
"opacity": 0.18
},
{
"type": "text",
"text": "P2",
"size": 11,
"weight": "bold",
"color": "orange"
}
]
},
{
"type": "vstack",
"align": "leading",
"spacing": 1,
"w": 210,
"children": [
{
"type": "text",
"text": "Billing address will not save",
"style": "subheadline",
"color": "primary",
"lines": 1
},
{
"type": "text",
"text": "Northwind",
"style": "caption",
"color": "secondary"
}
]
},
{"type": "spacer"}
]
},
{"type": "divider"},
{
"type": "hstack",
"spacing": 10,
"align": "center",
"padding": 9,
"children": [
{
"type": "zstack",
"align": "center",
"children": [
{
"type": "vstack",
"children": [],
"w": 32,
"h": 20,
"corner": 5,
"bg": "orange",
"opacity": 0.18
},
{
"type": "text",
"text": "P2",
"size": 11,
"weight": "bold",
"color": "orange"
}
]
},
{
"type": "vstack",
"align": "leading",
"spacing": 1,
"w": 210,
"children": [
{
"type": "text",
"text": "SSO login loops back to sign-in",
"style": "subheadline",
"color": "primary",
"lines": 1
},
{
"type": "text",
"text": "Globex",
"style": "caption",
"color": "secondary"
}
]
},
{"type": "spacer"}
]
},
{"type": "divider"},
{
"type": "hstack",
"spacing": 10,
"align": "center",
"padding": 9,
"children": [
{
"type": "zstack",
"align": "center",
"children": [
{
"type": "vstack",
"children": [],
"w": 32,
"h": 20,
"corner": 5,
"bg": "gray",
"opacity": 0.18
},
{
"type": "text",
"text": "P4",
"size": 11,
"weight": "bold",
"color": "gray"
}
]
},
{
"type": "vstack",
"align": "leading",
"spacing": 1,
"w": 210,
"children": [
{
"type": "text",
"text": "Feature request: dark mode for reports",
"style": "subheadline",
"color": "primary",
"lines": 1
},
{
"type": "text",
"text": "Initech",
"style": "caption",
"color": "secondary"
}
]
},
{"type": "spacer"}
]
},
{"type": "spacer"},
{
"type": "hstack",
"spacing": 5,
"align": "center",
"children": [
{
"type": "text",
"text": "Oldest waiting",
"style": "caption",
"color": "secondary"
},
{
"type": "timer",
"from": "2026-08-11T04:33:00Z",
"style": "relative",
"size": 13,
"color": "secondary"
}
]
}
]
}
} How it works
Lists are just a vstack of hstacks with dividers between them. There is no list node and no repeat construct — your server already has a loop, so it emits the rows it wants.
lines caps how many lines a text may wrap to. Past the cap the text first shrinks — to 60% at most — and only then truncates. Both happen against the width the text is *given*, so the subject column here is pinned with w. Leave both off and a row sizes itself to the longest subject you happen to have, which pushes the whole list off the edge of the widget.
This is the example that adapts. It names no hex value and sets no background on its root, so the widget keeps the system's own container material and every colour resolves at the moment of drawing. Use the Light and Dark control above the preview — nothing in the payload changes, and the widget is correct either way.
The priority pills get their tint from red, orange and gray at low opacity, drawn as a shape *behind* the label rather than around it. Fading a zstack that contains the text would fade the text too, since opacity applies to a node and everything inside it.
Put it on your Home Screen
This example is served live, with timestamps generated at the moment of the request. Add the URL as a hook in the app and it will work on a real phone.
https://webhookwidget.com/demo/queue Next
Habit grid — Five weeks of history built entirely from stacks.
All examples