✨ Build iOS/macOS widgets without Swift. Just JavaScript, JSX, and creativity.
ScriptWidget is a powerful widget development platform that lets you create native iOS and macOS widgets using JavaScript and JSX-like syntax. No Swift required!
Think of it as "React Native for Widgets" - but simpler and more flexible.
| Feature | Description |
|---|---|
| 🖥️ Cross-Platform | One codebase for iOS and macOS widgets |
| 🎨 JSX Support | Declarative UI with JavaScript XML syntax |
| ⚡ Native Performance | Compiled to native Swift/SwiftUI |
| 🔧 Rich APIs | Access device sensors, data sources, and more |
| 📱 Interactive Widgets | Tap, swipe, and interact with widgets |
| 🎨 Custom Styling | Full control over appearance |
| 📦 Template Gallery | Pre-built templates to get started |
| 🔄 Live Preview | See changes instantly in Xcode |
# Clone the repository
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- Select a scheme (
ScriptWidget/ScriptWidgetWidgetfor iOS,ScriptWidgetMacfor macOS) - Enable the
iCloud.ScriptWidgetcontainer andgroup.everettjf.scriptwidgetapp group so script storage works - Press
Cmd + Rto build and run - Browse the bundled example scripts under
Shared/ScriptWidgetRuntime/Resource/Script.bundle/(api/,component/,template/)
ScriptWidget/
├── Shared/
│ └── ScriptWidgetRuntime/ # Core runtime: JavaScriptCore host, JSX→SwiftUI
│ ├── Common/ # Script storage & package management
│ ├── Widget/Runtime/ # JS engine setup, Babel transform, execution
│ ├── Widget/API/ # JS APIs ($device, $file, $storage, ...)
│ ├── Widget/Component/ # Element → SwiftUI view mapping
│ └── Resource/ # Babel bundle + bundled example scripts
├── iOS/
│ ├── ScriptWidget/ # iOS app (editor, settings)
│ ├── ScriptWidgetWidget/ # Widget, Live Activity, Control Widget
│ └── ScriptWidgetShare/ # Share extension
├── macOS/
│ ├── ScriptWidgetMac/ # macOS app
│ └── ScriptWidgetMacWidget/ # macOS widget
├── Editor/editorfe/ # React + CodeMirror editor frontend
├── Resource/ # Marketing assets, screenshots
└── README.md
A script's entry point is the $render(...) call, which takes a JSX tree built from
runtime tags (vstack, hstack, zstack, text, image, gauge, chart, ...).
$render(
<vstack frame="max">
<text font="title">Hello, ScriptWidget! 👋</text>
</vstack>
);const result = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const model = JSON.parse(result);
$render(
<vstack>
<text font="title">{model.title}</text>
</vstack>
);$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>
);- Xcode 14+ (for iOS 16+ / macOS 13+)
- macOS 13+ (Ventura or later)
- iOS 16+ (for iOS widgets)
# Clone and setup
git clone https://github.com/everettjf/ScriptWidget.git
cd ScriptWidget
# Open in Xcode (pick the platform you want)
open iOS/ScriptWidget.xcodeproj # iOS
open macOS/ScriptWidgetMac.xcodeproj # macOS
# Build and run (Cmd + R)The editor frontend (React + CodeMirror) lives in Editor/editorfe:
cd Editor/editorfe
npm install
npm start # dev server at http://localhost:3000
npm run build- Run the app and create a new script from the in-app editor
- Write your widget in
main.jsxand call$render(...)with a JSX tree - Use the live preview to iterate, then add the widget from the Home Screen
Each script is a package stored under Scripts/<PackageName>/ (synced via iCloud /
the app group), with main.jsx as the entry point and an optional image/ folder.
- Entry point - call
$render(<tree/>)to draw the widget - Components -
vstack,hstack,zstack,text,image,gauge,chart, shapes, ... - Styling - element attributes such as
font,color,background,frame,padding - Widget sizes - read
$getenv("widget-size")(small / medium / large / accessory…) - Interactions - buttons and links via App Intents
| API | Description |
|---|---|
fetch() |
HTTP requests (fetch/$fetch) |
$storage |
Persisted key/value store (string & JSON) |
$file |
Read/write files in the script package |
$device |
Device info (model, battery, screen, dark mode, …) |
$location |
Location & geocoding |
$health |
HealthKit data (steps, heart rate, …) |
$system |
System info (timezone, app version, …) |
$import |
Import another file from the package |
console |
Logging (console.log / console.error) |
| Platform | Support | Notes |
|---|---|---|
| iOS | ✅ Full | iOS 16+ (iPhone, iPad) |
| macOS | ✅ Full | macOS 13+ (Mac) |
| watchOS | 🔄 Planned | Future release |
| visionOS | 🔄 Planned | Future release |
Contributions are welcome! Please read our Contributing Guide for details.
- 🐛 Report bugs
- 💡 Suggest features
- 🔧 Submit pull requests
- 📝 Write documentation
- 🎨 Share your widgets
ScriptWidget is released under the MIT License.
Built with:
- JavaScriptCore - Apple's JavaScript engine
- SwiftUI - Modern UI framework
- Xcode Gen - Project generation
Inspired by:
- React - Component-based UI
- React Native - Mobile development
- WidgetKit - Apple's widget framework
有问题?去 Issues 提问!
Made with ❤️ by Everett
Project Link: https://github.com/everettjf/ScriptWidget

