Skip to main content

Button

A tappable component that runs a piece of JS when tapped.

Can't open URLs

Button can only run JS — it can't open URLs directly (it's built on AppIntent, a system limitation). For "tap to navigate", use a stack container as a button — vstack / hstack / zstack / tstack / grid all have an "Open URL" property, and the entire container becomes tappable.

Platform limits

Buttons on home screen widgets require iOS 17+. Lock screen widgets and Dynamic Island widgets currently can't host tappable buttons (system limitation).

Usage​

Tap the ➕ in the top-right of the editor and add button. You can place any children inside it (text / icon / image) to define its appearance. Then in the button's properties, write the JS to run.

Common properties​

PropertyDescription
ChildrenThe button's visuals (text, icon, etc.)
Content (JS code)The JS snippet run on tap
Styleplain (no border) / noflash (no flash) / normal (system button)
Background / Corner radiusVisual tweaks

Button code vs. main JS​

Main JSButton code
When it runsWhen the widget refreshesWhen the user taps the button
Used forFetching data / API calls, assigning to this.xxxChanging local state / triggering actions
LengthUsually longerUsually a few lines

After the button code runs, Omni automatically refreshes the widget so the new state takes effect.

Example: toggle a "liked" state​

Main JS:

this.state = getValue("liked") || "heart"

Button code:

const cur = getValue("liked") || "heart"
setValue("liked", cur === "heart" ? "heart.fill" : "heart")

Inside the button, place an icon with content ${state} — each tap toggles between "♡" and "❤".

Want "tap to open a URL"?​

Don't use a button — use a stack container instead:

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

Or open a third-party app:

hstack (Open URL: weixin://)
├─ icon (message.fill)
└─ text ("Open WeChat")

More in stack.md → Open URL.