Skip to content

swiftwasm/JavaScriptKit

JavaScriptKit

Run unit tests Documentation

Swift framework to interact with JavaScript through WebAssembly.

Quick Start

Check out the Hello World tutorial for a step-by-step guide to getting started.

Overview

JavaScriptKit provides a seamless way to interact with JavaScript from Swift code when compiled to WebAssembly. It allows Swift developers to:

  • Access JavaScript objects and functions
  • Create closures that can be called from JavaScript
  • Convert between Swift and JavaScript data types
  • Use JavaScript promises with Swift's async/await
  • Work with multi-threading
import JavaScriptKit

// Access global JavaScript objects
let document = JSObject.global.document

// Create and manipulate DOM elements
var div = document.createElement("div")
div.innerText = "Hello from Swift!"
_ = document.body.appendChild(div)

// Handle events with Swift closures
var button = document.createElement("button")
button.innerText = "Click me"
button.onclick = .object(JSClosure { _ in
    JSObject.global.alert!("Button clicked!")
    return .undefined
})
_ = document.body.appendChild(button)

Learn more: JavaScript Interop Cheat Sheet

BridgeJS Plugin

Note: BridgeJS is experimental. APIs may change in future releases.

BridgeJS provides easy interoperability between Swift and JavaScript/TypeScript. It enables:

  • Export Swift to JavaScript - Expose Swift functions, classes, and types to JavaScript; the plugin also generates TypeScript definitions (.d.ts) for the exported API.
  • Import JavaScript into Swift - Make JavaScript/TypeScript APIs (functions, classes, globals like document or console) callable from Swift with type-safe bindings. You can declare bindings with macros in Swift or generate them from a TypeScript declaration file (bridge-js.d.ts).

For architecture details, see the BridgeJS Plugin README. For package and build setup, see Setting up BridgeJS in the documentation.

Exporting Swift to JavaScript

Mark Swift code with @JS to make it callable from JavaScript:

import JavaScriptKit

@JS class Greeter {
    @JS var name: String

    @JS init(name: String) {
        self.name = name
    }

    @JS func greet() -> String {
        return "Hello, \(name)!"
    }
}

JavaScript usage:

const greeter = new exports.Greeter("World");
console.log(greeter.greet()); // "Hello, World!"

Learn more: Exporting Swift to JavaScript

Importing JavaScript into Swift

Declare bindings in Swift with macros such as @JSFunction, @JSClass, @JSGetter, and @JSSetter:

import JavaScriptKit

@JSClass struct Document {
    @JSFunction func getElementById(_ id: String) throws(JSException) -> HTMLElement
    @JSFunction func createElement(_ tagName: String) throws(JSException) -> HTMLElement
}
@JSGetter(from: .global) var document: Document

@JSClass struct HTMLElement {
    @JSGetter var innerText: String
    @JSSetter func setInnerText(_ newValue: String) throws(JSException)
    @JSFunction func appendChild(_ child: HTMLElement) throws(JSException)
}

@JS func run() throws(JSException) {
    let button = try document.createElement("button")
    try button.setInnerText("Click Me")
    let container = try document.getElementById("app")
    try container.appendChild(button)
}

You can also generate the same macro-annotated Swift from a TypeScript file (bridge-js.d.ts). See Generating bindings from TypeScript in the documentation.

Learn more: Importing JavaScript into Swift

Try It Online

Use the BridgeJS Playground to preview what interfaces will be exposed on the Swift/TypeScript sides.

Examples

Check out the examples for more detailed usage patterns.

Contributing

Contributions are welcome! See CONTRIBUTING.md for details on how to contribute to the project.

Sponsoring

Become a gold or platinum sponsor and contact maintainers to add your logo on our README on Github with a link to your site.