This project is in alpha — APIs may change without notice.
native-window

Getting Started

Install native-window and create your first native window

Prerequisites

  • Bun (v1.3+) or Node.js (v18+)
  • macOS or Windows (Linux is not supported)
  • On Windows 10, the WebView2 runtime may need to be installed (see Runtime Check below)

Installation

Install the core package:

bun add @fcannizzaro/native-window

For typed IPC channels (optional):

bun add @fcannizzaro/native-window-ipc

If your webview app uses React, add the hooks package for idiomatic React integration:

bun add @fcannizzaro/native-window-ipc-react

If you use native-window-ipc, a schema library is required — schemas provide both TypeScript types and runtime validation for every IPC event. Zod is recommended, but Valibot and any library implementing safeParse() also work. See Supported Schema Libraries for details.

bun add zod

Runtime Check

On macOS, the webview engine (WKWebView) is always available. On Windows 10, you may need to install the WebView2 runtime. Use checkRuntime() to detect availability and ensureRuntime() to auto-install if missing:

import { checkRuntime, ensureRuntime } from "@fcannizzaro/native-window";

const info = checkRuntime();
// { available: true,  version: "128.0.2739.42", platform: "windows" }
// { available: false, version: undefined,        platform: "windows" }
// { available: true,  version: undefined,        platform: "macos" }

if (!info.available) {
  console.log("WebView2 not found, installing...");
  const result = ensureRuntime(); // downloads ~2MB bootstrapper, runs silently
  console.log("Installed:", result.version);
}

On Windows 11, WebView2 is pre-installed. On macOS, both functions return { available: true } immediately.

Create a Window

The NativeWindow class handles initialization and event pumping automatically. Just create an instance and start using it:

import { NativeWindow } from "@fcannizzaro/native-window";

const win = new NativeWindow({
  title: "My App",
  width: 800,
  height: 600,
});

win.loadHtml(`
  <h1>Hello from native webview!</h1>
  <p>This is running inside a native OS window.</p>
`);

win.onClose(() => {
  console.log("Window closed");
  process.exit(0);
});

When the first NativeWindow is created, the native subsystem initializes and starts pumping events at ~60fps. When all windows are closed, the pump stops automatically.

Load a URL

Instead of inline HTML, you can load any URL:

win.loadUrl("https://example.com");

Basic IPC

The webview exposes a raw IPC bridge for message passing. On the webview side, use window.ipc.postMessage() to send messages and window.__native_message__ to receive them:

import { NativeWindow } from "@fcannizzaro/native-window";

const win = new NativeWindow({ title: "IPC Demo" });

win.loadHtml(`
  <button onclick="window.ipc.postMessage('hello from webview')">
    Send Message
  </button>
  <pre id="log"></pre>
  <script>
    window.__native_message__ = function(msg) {
      document.getElementById('log').textContent += msg + '\\n';
    };
  </script>
`);

// Receive messages from the webview
win.onMessage((msg) => {
  console.log("From webview:", msg);
  // Send a message back
  win.postMessage("Echo: " + msg);
});

win.onClose(() => process.exit(0));

This raw bridge sends and receives plain strings. For structured, type-safe messaging, see Typed IPC.

Next Steps

  • NativeWindow API — full API reference for window options, methods, and events
  • Typed IPC — compile-time checked messaging with event maps and runtime validation
  • React Hooks — React hooks for typed IPC in webview apps
  • Security — threat model and best practices for safe webview usage

On this page