Skip to main content

Stack (Container)

A container groups multiple children together. There are four layout modes:

TypeLayoutUse case
vstackVertical ↕Title + subtitle, list rows
hstackHorizontal ↔Icon + text, left/right alignment
zstackLayered ⊕Background image + foreground content
tstackRich text concatenation ✏️Mixed fonts / colors within a single text run

Common properties

PropertyDescription
ChildrenAny components inside, nestable
SpacingDistance between children
Padding (padding/pacings)Inner padding on 4 sides, e.g. 10,10,10,10
Alignmentcenter / leading / trailing etc.
Background / Corner radiusContainer background
Material (blur)Frosted glass background (thick / thin / regular)
Rotation / Offset / OpacityVisual tweaks
Open URL (openUrl)Makes the whole container tappable — opens a URL when tapped. See the dedicated section below

openurl

All stack containers (vstack / hstack / zstack / tstack / grid) support the Open URL property. Once set, the entire container becomes a tappable region; when the user taps it, iOS opens the URL.

Why on the container and not on a button?

The button component can only run JS — it can't open URLs (it's built on AppIntent, a system limitation). So "tap to navigate" is always done through stack containers.

Common URLs

URLBehavior
https://2f0.cnOpens a web page
weixin://Opens WeChat
mailto:foo@bar.comComposes an email
awidget://runjs/medium/{Widget.id}Re-runs the current widget's JS
awidget://openmini?...Opens a WeChat Mini Program (the system appends &from=omni automatically)
{link}Decided by your JS

Example: make a "button"

The simplest "button": a zstack + text + openUrl.

zstack (Open URL: https://2f0.cn)
└─ text ("Visit the site")

A bit fancier: icon + text + rounded background + navigation.

hstack (Background: blue, Corner radius: 10, Padding: 10,10,15,15, Open URL: weixin://)
├─ icon (message.fill, white)
└─ text ("Open WeChat", white)

vstack — Vertical

The most common. Children stack top to bottom.

┌─────────┐
│ text 1 │
│ text 2 │ ← vstack
│ icon │
└─────────┘

hstack — Horizontal

Children stack left to right. Combine with spacer for "edge alignment".

[ icon | text | spacer | button ]   ← hstack

zstack — Layered

Children are stacked on top of each other — later ones on top. Common uses:

  • Background image + text
  • Translucent overlay
  • Progress bar (base color + progress color)
   ┌───────┐
│ bg │ ← first layer (background)
│ txt │ ← second layer (on top)
└───────┘

tstack — Rich text concatenation

Totally different from the other three — tstack is not a layout container. It glues multiple text children into a single continuous text run (built on SwiftUI's Text + Text). Each segment can have its own font size / font / color, but everything is laid out and wrapped as a single piece of text.

Three text components in a vstack / hstack are 3 independent Text views — they wrap and align independently. Three text components in a tstack are 1 single text run — they won't wrap between segments, and the whole thing only wraps when the entire run is too long.

Children

Only text is accepted (other types are ignored). There's no separator between children — if you want a space, add it inside the value.

Example: big number + small unit

tstack:
├─ text (content: "32", size 36, color primary)
└─ text (content: "°C", size 14, color gray)

Renders: 32°C (big number, small unit, snug together). With an hstack, the small unit would be centered separately and float far from the number — not natural.

Example: bold one word

tstack:
├─ text (content: "You have ")
├─ text (content: "{count}", large size, red color)
└─ text (content: " new messages")

Renders: You have 5 new messages, with the number standing out.

Notes

  • Want a space between segments? Add it to the start or end of the value — tstack won't add one for you.
  • Want them to wrap onto separate lines? Use vstack, not tstack.
  • tstack ignores icon / image / containers — only text is recognized.

Containers can also loop

Any container (vstack / hstack / zstack / grid) can be given a loop data source to repeat its children N times over an array. See Loop.

Example: classic "icon + title + subtitle" card

hstack:
├─ icon (large)
└─ vstack:
├─ text ("Title")
└─ text ("Subtitle", small size, gray)

Example: cover image + title (zstack)

zstack:
├─ image (cover, fill)
└─ vstack:
├─ spacer
└─ text ("Title", white)

Result: text floats at the bottom of the cover image.