> ## Documentation Index
> Fetch the complete documentation index at: https://webview.js.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Application — WebviewJS Root Object and Event Loop

> Application owns the native event loop, all windows, tray icons, and menus. Reference for lifecycle, factory methods, and application events.

`Application` is the root of every WebviewJS program. It owns the native event loop, all `BrowserWindow` instances, tray icons, web contexts, and menus you create during the session. You must construct exactly one `Application` before calling any other WebviewJS API, and keep it alive for the duration of your program.

```ts theme={null}
import { Application } from '@webviewjs/webview';

const app = new Application();
```

***

## Constructor

```ts theme={null}
new Application(options?: ApplicationOptions)
```

`ApplicationOptions` is accepted by the constructor but is currently unused. You can safely pass `null` or omit the argument entirely.

***

## Lifecycle Methods

### `run(options?)`

Starts the event pump by calling `pumpEvents()` on a `setInterval` and returns immediately, leaving the Node.js event loop free for async work such as file I/O and timers. This is the recommended way to drive the event loop in most Node.js applications.

```ts theme={null}
app.run(options?: { interval?: number; ref?: boolean }): void
```

<ParamField body="interval" type="number" default="16">
  How often to pump OS events, in milliseconds. The default of 16 ms targets \~60 FPS.
</ParamField>

<ParamField body="ref" type="boolean" default="true">
  When `false`, the underlying timer is [unref'd](https://nodejs.org/api/timers.html#timeoutunref) and will not prevent the Node.js process from exiting on its own.
</ParamField>

***

### `runSync()`

Runs the native Tao event loop on the current thread and **blocks JavaScript** until the application exits. The Node.js event loop is unavailable while this call is in progress.

```ts theme={null}
app.runSync(): void
```

<Note>
  Use `run()` in most Node.js applications. Reserve `runSync()` for cases where you explicitly want the GUI loop to own the thread.
</Note>

***

### `stop()`

Clears the pump interval started by `run()`. The `Application` object and all windows remain valid — you can restart the pump by calling `run()` again.

```ts theme={null}
app.stop(): void
```

***

### `exit()`

Stops the pump, hides all tracked windows, and marks the application as exited. Subsequent `pumpEvents()` calls return `false`. All resources owned by the application (windows, webviews, tray icons, web contexts) are disposed.

```ts theme={null}
app.exit(): void
```

***

### `pumpEvents()`

Processes one batch of OS events without blocking. Returns `true` while the application is alive, `false` when the application should stop. You normally do not call this directly — `run()` drives it automatically.

```ts theme={null}
app.pumpEvents(): boolean
```

***

### `whenReady(options?)`

Returns a `Promise` that resolves after the native event loop fires its first `resumed` lifecycle callback, indicating that the platform is ready to display windows. By default, calling `whenReady()` also starts the event pump automatically.

```ts theme={null}
app.whenReady(options?: ApplicationWhenReadyOptions): Promise<void>
```

```ts theme={null}
type ApplicationWhenReadyOptions =
  | { autoRun?: true; interval?: number; ref?: boolean }
  | { autoRun: false; interval?: never; ref?: never };
```

<ParamField body="autoRun" type="boolean" default="true">
  When `true` (default), `whenReady()` calls `run()` internally. Set to `false` when you plan to drive the loop manually with `run()` or `pumpEvents()`.
</ParamField>

<ParamField body="interval" type="number">
  Forwarded to `run()`. Only valid when `autoRun` is `true`.
</ParamField>

<ParamField body="ref" type="boolean">
  Forwarded to `run()`. Only valid when `autoRun` is `true`.
</ParamField>

<Note>
  If the application is already ready when you call `whenReady()`, the promise still resolves asynchronously on the next microtask tick.
</Note>

***

### `isReady()`

Returns `true` if the native event loop has already emitted its `resumed` event.

```ts theme={null}
app.isReady(): boolean
```

***

## Factory Methods

Use these methods to create WebviewJS resources. Resources created through the application are automatically tracked and disposed when `app.exit()` is called.

### `createBrowserWindow(options?)`

Creates and returns a new [`BrowserWindow`](/api/browser-window) wrapping an OS-level window.

```ts theme={null}
app.createBrowserWindow(options?: BrowserWindowOptions): BrowserWindow
```

See [BrowserWindow](/api/browser-window) for the full options reference.

***

### `createChildBrowserWindow(options?)`

Creates a child/popup window. The webview inside a child window occupies a precise region you specify rather than filling the whole window. Useful for panels, overlays, and embedded views.

```ts theme={null}
app.createChildBrowserWindow(options?: BrowserWindowOptions): BrowserWindow
```

***

### `createWebContext(options?)`

Creates an isolated browser-data context that can be shared across multiple webviews, giving them a common cookie jar, cache, and local storage.

```ts theme={null}
app.createWebContext(options?: WebContextOptions): WebContext
```

<Note>
  Always create contexts through `app.createWebContext()`. Calling `new WebContext()` directly is not supported.
</Note>

See [WebContext](/api/web-context) for the full API reference.

***

### `createTrayIcon(options)`

Creates a system tray icon with an optional menu and tooltip.

```ts theme={null}
app.createTrayIcon(options: TrayIconOptions): TrayIcon
```

***

### `setMenu(options?)`

Sets the global application menu. Pass `null` or omit the argument to remove it.

```ts theme={null}
app.setMenu(options?: MenuOptions): void
```

See the [Menus guide](/guides/menus) for the full `MenuOptions` shape.

***

## Application Events

`Application` extends the standard Node.js `EventEmitter`. Subscribe to application-level events with `.on()`, `.once()`, or any other EventEmitter method.

### Event reference

| Event                         | Payload                                                               | Fired when                                               |
| ----------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------- |
| `ready`                       | `ApplicationEvent`                                                    | The native event loop emits its first `resumed` callback |
| `window-close-requested`      | `ApplicationEvent`                                                    | A user clicks the OS close button on any window          |
| `application-close-requested` | `ApplicationEvent`                                                    | The last open window is closed                           |
| `custom-menu-click`           | `ApplicationEvent` (`customMenuEvent.id`, `customMenuEvent.windowId`) | A custom menu item is selected                           |

The `ApplicationEvent` payload shape:

```ts theme={null}
interface ApplicationEvent {
  event: WebviewApplicationEvent; // numeric enum value
  customMenuEvent?: {
    id: string;       // the menu item's id string
    windowId: number; // the window the menu belongs to
  };
}
```

### Usage example

```ts theme={null}
import { Application } from '@webviewjs/webview';

const app = new Application();

app.on('ready', () => {
  console.log('Native event loop is ready');
});

app.on('window-close-requested', (event) => {
  console.log('Close requested for window', event.customMenuEvent?.windowId);
});

app.on('application-close-requested', () => {
  // All windows have been closed — clean up and exit.
  app.exit();
});

app.on('custom-menu-click', ({ customMenuEvent }) => {
  if (customMenuEvent) {
    console.log(`Menu item "${customMenuEvent.id}" clicked in window ${customMenuEvent.windowId}`);
  }
});

await app.whenReady();
```

### Available EventEmitter methods

| Method                            | Description                                      |
| --------------------------------- | ------------------------------------------------ |
| `on(event, listener)`             | Add a persistent listener                        |
| `once(event, listener)`           | Add a one-time listener                          |
| `off(event, listener)`            | Alias for `removeListener`                       |
| `addListener(event, listener)`    | Add a persistent listener (alias for `on`)       |
| `removeListener(event, listener)` | Remove a specific listener                       |
| `removeAllListeners(event?)`      | Remove all listeners for an event, or all events |
| `listenerCount(event)`            | Number of listeners for an event                 |
| `listeners(event)`                | Copy of the listener array for an event          |
| `rawListeners(event)`             | Listener array including once-wrappers           |
| `emit(event, payload)`            | Synchronously invoke all listeners               |
| `eventNames()`                    | Array of registered event names                  |

All registration and removal methods return `this` and are chainable.

***

### Legacy `onEvent()` / `bind()`

<Note>
  These methods are provided for backwards compatibility. Prefer the EventEmitter API (`.on()`, `.once()`, etc.) for new code.
</Note>

Register a callback for application-level events. Both names are equivalent aliases.

```ts theme={null}
app.onEvent(handler: (event: ApplicationEvent) => void): void
app.bind(handler: (event: ApplicationEvent) => void): void
```

Compare the numeric `event` field against the exported `WebviewApplicationEvent` enum:

```ts theme={null}
import { WebviewApplicationEvent } from '@webviewjs/webview';

app.onEvent((event) => {
  if (event.event === WebviewApplicationEvent.ApplicationCloseRequested) {
    app.exit();
  }
  if (event.event === WebviewApplicationEvent.CustomMenuClick) {
    console.log(event.customMenuEvent?.id);
  }
});
```

| `WebviewApplicationEvent` value | Fired when                                           |
| ------------------------------- | ---------------------------------------------------- |
| `WindowCloseRequested`          | User clicks the OS close button on a window          |
| `ApplicationCloseRequested`     | The last window was closed                           |
| `CustomMenuClick`               | A custom menu item was clicked                       |
| `Ready`                         | The native event loop emitted its first resume event |

***

## Resource Management

### `Symbol.dispose`

`Application` implements the [TC39 Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management) protocol. You can use a `using` declaration to guarantee cleanup even if an exception is thrown:

```ts theme={null}
{
  using app = new Application();
  // ... your application code ...
} // app.exit() is called automatically here
```

### Root-owned disposal

Every resource you create through an `Application` instance — windows, webviews, tray icons, web contexts, and menus — is owned by that application. Calling `app.exit()` (or triggering `[Symbol.dispose]`) disposes all of them in one shot.

Disposal is **idempotent**: calling `exit()` more than once is safe. After disposal, retained resource wrapper objects (e.g. `BrowserWindow`, `Webview`) report `isDisposed() === true` and throw if you call further methods on them. Attempting to create new resources after `exit()` also throws.

```ts theme={null}
app.exit();
// All owned resources (windows, webviews, tray icons, web contexts) are now disposed.
```

***

## Complete Example

The following example shows the recommended pattern for a WebviewJS application using `whenReady()`:

```ts theme={null}
import { Application } from '@webviewjs/webview';

const app = new Application();

// Handle menu clicks
app.on('custom-menu-click', ({ customMenuEvent }) => {
  if (customMenuEvent?.id === 'quit') {
    app.exit();
  }
});

// Exit when the last window closes
app.on('application-close-requested', () => {
  app.exit();
});

// whenReady() starts the event pump and resolves once the platform is ready
await app.whenReady();

const win = app.createBrowserWindow({
  title: 'My App',
  width: 1280,
  height: 720,
});

win.createWebview({ url: 'https://example.com' });
```
