ScriptWidget Studio on the Mac: the script file tree, the JSX editor and the live widget preview side by side.

ScriptWidget: Build Native iOS and macOS Widgets in JavaScript and JSX

ScriptWidget renders a JavaScript and JSX tree as native WidgetKit views, so you can build widgets for iPhone, iPad and Mac without writing Swift. Here is what it does, how to build it, where it falls short, and what the MIT licence lets you do.

Key takeaways
  • ScriptWidget renders a JSX tree as native SwiftUI views, so one JavaScript codebase produces real WidgetKit widgets for iPhone, iPad and Mac rather than a WebView or a bitmap.
  • ScriptWidget Studio on the Mac adds CodeMirror editing with diagnostics, a runtime console, live preview for every widget family, and an AI generation loop against any OpenAI-compatible model.
  • A widget is a versioned package: widget.json declares the entry point, families, permissions and allowed network hosts, and the community Gallery installs verified widgets and AI Skills in one click.
  • The floor is high and the scope is narrow — Xcode 27 for the current source branch, macOS 26 for Studio, iOS 16 for widgets — and watchOS and visionOS are explicitly not on the roadmap.

Widgets are the one corner of the Apple platforms that still assumes you write Swift. A WidgetKit extension is a Swift target, laid out in SwiftUI, and the tooling around it — previews, timelines, App Intents — follows from that assumption. ScriptWidget bets the other way: you describe the widget as a JSX tree in JavaScript, and the app renders that tree with native SwiftUI views. What ends up on the Home Screen is a real widget, not a WebView and not a screenshot.

It is an open-source project by Everett (everettjf), MIT licensed, and it is more than a runtime: there is a Mac development environment, a package format with permissions, a community gallery and an AI-assisted generation loop sitting on top of the same engine. The project's website points at an App Store build for using the app; the repository is the platform, and this article is about the repository.

What It Does

The core idea fits in a single call. You compose a tree from familiar elements — vstack, hstack, text, image, gauge — hand it to $render, and ScriptWidget maps each element onto the matching SwiftUI view. Styling is done through attributes that read like SwiftUI modifiers: a font, a colour, a frame, an alignment. There is no Swift file to keep in step with the JavaScript, and nothing to regenerate when the layout changes.

A versioned runtime API covers what a widget normally needs: storage, files, networking, device state, location, health and system information, plus data sources. Interactivity goes past the static case as well — links, buttons and toggles, App Intents, Live Activities and Control Widgets — so the same language that draws the widget can drive what it does when it is tapped.

Around the runtime sit the parts that make it a platform rather than a library. A template gallery gives you a working starting point, a community gallery installs verified widgets and AI Skills in one click, and a Data Source Plugin system turns a third-party API into a declarative connector you can test in a request lab on the Mac. Packages are versioned, and legacy scripts keep working rather than being stranded.

How to Install It

If you simply want to use ScriptWidget, install the App Store version from the official App Store listing. Building from source is only for working on the platform itself — the runtime, Studio or gallery — and requires Xcode. The current development branch asks for Xcode 27, ScriptWidget Studio needs macOS 26, and iOS widgets need iOS 16 or later. There is no Homebrew formula.

git clone https://github.com/everettjf/ScriptWidget.git
cd ScriptWidget

# iOS app + widget + share extension
open iOS/ScriptWidget.xcodeproj

# macOS app + widget
open macOS/ScriptWidgetMac.xcodeproj

Two capabilities have to be enabled before script storage works: the iCloud.ScriptWidget container and the group.everettjf.scriptwidget app group. After that, build and run, then read the bundled example scripts under Shared/ScriptWidgetRuntime/Resource/Script.bundle/, which are split into api, component and template folders — a fair map of what the runtime offers before you write anything of your own.

How to Use It

ScriptWidget Studio is the Mac answer to the build-and-preview loop, and it is where most authoring will happen. The window is a file tree on the left, a CodeMirror 6 editor in the middle and a preview pane on the right: schema completions, diagnostics and formatting in the editor, a runtime console and timing information underneath, and live preview for one widget family or all of them at once. A configuration panel edits widget.json — families, permissions, network domains, plugins, preview parameters — so the manifest does not have to be hand-written.

The first-launch guide is worth running even if you intend to go straight to your own project: it builds a complete tutorial widget and walks through editing it and adding it to the desktop in about five minutes. From there the loop is short — write main.jsx, preview, adjust.

$render(
  <vstack frame="max">
    <text font="title">Hello, ScriptWidget! 👋</text>
  </vstack>
);

The runtime exposes its APIs as dollar-prefixed globals, so the gap between reading about them and using them is small. Storage is the one worth seeing, because it shows how a widget keeps state across refreshes:

$storage.setString("greeting", "Hello ScriptWidget");
const greeting = $storage.getString("greeting");

$render(
  <vstack frame="max" background="#0f172a">
    <text font="caption" color="#94a3b8">Storage</text>
    <text font="title3" color="#e2e8f0">{greeting}</text>
  </vstack>
);

The Screenshots

The project documents itself visually. The Mac set shows Studio with the file tree, the JSX editor and the live preview side by side — the same window the cover of this article is built from — alongside pages for the API surface, the component set and the template gallery. The iOS set shows the code editor on the phone, a widget on the Home Screen, and a marketplace grid laying out small, medium and large widgets together. Both sets live under Resource/ in the repository, so the imagery is in the source tree rather than only on a store listing.

How It Works

The runtime is JavaScriptCore plus a Babel transform. Your JSX is compiled into the JavaScript that builds a tree of element objects, then the native host walks that tree and instantiates the matching SwiftUI views. Nothing here is a WebView and nothing is rasterised after the fact: the view that lands on the Home Screen is composed by WidgetKit from real SwiftUI primitives, which is what lets it behave like a widget rather than a picture of one — honour the tinting modes, adapt to the widget family, and take part in the system's own rendering.

That distinction is why the project is worth writing about at all. A JavaScript-driven widget that renders through a WebView or a static bitmap can look right in a screenshot and still fail every test that matters — dark mode, tinted mode, the wider families, accessibility. Rendering JSX straight to SwiftUI sidesteps that class of problem at the source, and it is also why the same script runs unchanged on iPhone, iPad and Mac.

Packages and the Gallery

A widget is a folder under Scripts/<PackageName>/ that syncs through iCloud and the app group. New projects use Package 2.0, where widget.json is the authoritative manifest: it names the entry point, the supported families, the permissions the widget asks for, the network hosts it may reach and any Data Source Plugins it uses. That is a security shape rather than a convenience — a package states what it needs, and the runtime can hold it to that.

The community Gallery is built on the same format. Packages are verified, installing one is a click, and the same catalogue carries AI Skills — reusable instruction sets for the generation loop that you can import, author, export and share. Packages that predate widget.json stay readable and migrate during import and export instead of breaking.

AI-Assisted Authoring

The AI features are not a chat window bolted onto the editor. You configure a provider profile against an OpenAI-compatible model, then generate, run, diagnose and refine a widget inside Studio, with the console and the preview feeding the loop. The Skills are what make it repeatable: rather than re-explaining your conventions in every prompt, you keep them as a shared instruction set that travels with the project.

Where It Falls Short

Start with the scope, because it is deliberate: watchOS and visionOS are not in the current roadmap, and the README says so rather than leaving it implied. This is a tool for iPhone, iPad and Mac widgets, not for the whole Apple surface. Studio is a Mac application too, so authoring means sitting at a Mac even when the widget's destination is a phone or a tablet.

Then the floor. The current development branch wants Xcode 27, Studio wants macOS 26 and widgets want iOS 16 — none of it is aimed at an older machine. Building from source also means cloning and running an Xcode project rather than a package-manager command, and the project does not pretend otherwise.

Two smaller caveats. The AI generation path needs your own OpenAI-compatible provider, so that feature is only as good as the model and key you bring to it rather than something the app supplies. And the Gallery is a trust model as much as a feature: verified or not, installing someone else's widget means running someone else's JavaScript, which is exactly why Package 2.0 bothers to declare permissions and host allowlists in the first place.

The Licence: What You Can Do

The source code is MIT licensed, © Everett. The practical reading is short and permissive: use it commercially, modify it, redistribute it — including inside a closed-source app — provided you keep the copyright notice and the licence text with any substantial portion you copy. There is no copyleft and no obligation to publish your changes.

There is one carve-out, and it is worth stating plainly because it is easy to miss. The MIT grant covers the source code; the ScriptWidget name, its logos, its screenshots and the App Store marketing assets are excluded and stay with the author. You can fork the platform and ship it, but you cannot pass it off as ScriptWidget or reuse its brand imagery to do so.

Should You Build It

If you have ever wanted a widget no App Store developer was going to build for you, and you are comfortable in JavaScript, this is the shortest path to one on the Apple platforms — and the fact that the result is genuinely native, rather than a WebView wearing a widget's clothes, is what makes the detour worthwhile. If you are a developer, the interesting artefact is the runtime: a JavaScriptCore host that maps a declarative tree onto SwiftUI, wrapped in a package format that thinks about permissions, is a shape worth studying even if you never ship a widget. The limits are honest and stated up front — no watchOS or visionOS, a Mac-only studio, a recent-Xcode floor — so the decision is mostly about which side of them you are on.

Project facts

License
MIT
Platform
iOS 16+ / macOS 26+ (Studio)
Written in
JavaScript, JSX, Swift (SwiftUI runtime)
Version reviewed
main @ 2026-09-21

Install

# Open the App Store listing:
open https://apps.apple.com/us/app/scriptwidget/id1555600758

License summary

MIT is a permissive licence: you can use the code in commercial and closed-source apps, modify it, and redistribute it, as long as you keep the copyright notice and the licence text with any substantial portion you copy. There is no warranty. The project carves its name, logos, screenshots and App Store marketing assets out of the MIT grant, so those stay with the author.