Ultralight offers a safe, high-performance, type-checked JavaScript bridge for C++20 and low-level C. You can use it to expose application data and functions, make calls into JavaScript, and more.

> 🚧 Preview API
>
> The JavaScript API is a preview. Names and behavior may still change after 2.0.

## JavaScript API Quick-Start

Start by defining an "API" (think of it like a JavaScript namespace for all of your application's data/functions), attach it to a View, then load your content per-usual:

```cpp
// Include "Ultralight/JS.h" to access the optional JS API headers
#include <Ultralight/JS.h>

js::API app("app");

app["version"] = "2.1.0";
app["add"] = [](double a, double b) { return a + b; };

if (app.AttachTo(view.get()))
  view->LoadURL("file:///app.html");
```

Page script sees a `app` namespace on `window`:

```js
app.add(2, 3);  // 5
```

> 🚧 Only Local Content Can Access Your Custom API
>
> By default, only local pages (eg, `file://`) can access native API objects (remote HTTP/HTTPS websites are blocked). To whitelist other URLs, pass origin rules to `AttachTo()` (see [Choosing Which Pages Get the API](/docs/2.0/extending-javascript-with-native-api#content-choosing-which-pages-get-the-api)).

## Type-Checked on Both Sides

The JavaScript API is **strongly typed**. The types you declare are checked on both sides— once, when you build your C++ code and again, during every runtime JavaScript call.

 * At build time, a bad type-conversion in C++ will throw a compiler error with a `static_assert` explaining the problem.
 * At call time, a page calling `myApp.add(2, "loud")` throws a JavaScript `TypeError` explaining the expected type (`expected number, got 'loud'`).

## Rules to Know

- **Call the API on the Renderer's thread.** `API::Emit()` is the exception and works from any thread. Copying, moving, and destroying a handle is safe from any thread too.
- **A handle never keeps its page alive.** Once the page navigates away (or its View is destroyed), the handle's page is gone and anything you do with it fails safely.
- **The API never throws C++ exceptions.** A call that can fail returns a [`js::Result`](/api/cpp/2_0_0/namespaceultralight_1_1js.html#afb5f0010308cecec954e64d983143d4b), which holds either the value or a `js::Error`.

> 📘 Build Requirements
>
> The bridge requires C++20— on Windows, that means Visual Studio 2022 (MSVC 19.30) or newer. Automatic struct and enum conversion needs Clang, GCC, or MSVC 19.40+ (they don't convert automatically on MSVC 19.30 through 19.39). Every file that uses the bridge must use the same C++ exception setting.

## Where to Go

- [Extending JavaScript with Native API](/docs/2.0/extending-javascript-with-native-api) — Create an API, bind functions and values, and attach it to a View.
- [Calling into the Page](/docs/2.0/calling-into-the-page) — Call functions on the page, run scripts, and receive typed results.
- [Working with JavaScript Values](/docs/2.0/working-with-javascript-values) — Convert types, inspect objects, and read arrays using `js::Value`.
- [Passing Data Across the Bridge](/docs/2.0/passing-data-across-the-bridge) — Convert standard and library types automatically, and pass binary buffers and DOM elements.
- [Custom Type Conversions](/docs/2.0/custom-type-conversions) — Teach the bridge to convert custom native value types with `js::TypeTraits`.
- [Async Callbacks](/docs/2.0/async-callbacks) — Return Promises to the page, use C++20 coroutines, and run tasks on worker threads.
- [Exposing Native Classes](/docs/2.0/exposing-native-classes) — Bind C++ classes that the page can instantiate with `new`, and manage instance ownership.
- [Emitting Events](/docs/2.0/emitting-events) — Push events from native code to listeners on the page.
- [API Schemas and TypeScript](/docs/2.0/api-schemas-and-typescript) — Export an API schema as JSON and generate TypeScript declarations for editor support.
- [JavaScript Errors and Diagnostics](/docs/2.0/javascript-errors-and-diagnostics) — Throw structured errors into the page, inspect error codes, and catch typos with diagnostics.
- [Using JavaScriptCore Directly](/docs/2.0/using-javascriptcore-directly) — Work directly with the raw JavaScriptCore C API underneath, which remains supported and included.

Coming from JSHelpers or raw JavaScriptCore code? The porting tables live in [Porting from 1.4 to 2.0](/docs/2.0/migrating-from-1-4-to-2-0). And if your UI needs no page script at all, the [DOM API](/docs/2.0/about-the-dom-api) controls pages without any JavaScript.
