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

NativeWindow

API reference for the native window addon

NativeWindow Class

The NativeWindow class creates a native OS window with an embedded webview. It wraps the Rust napi-rs addon and manages the lifecycle automatically:

  • Auto-init — the native subsystem initializes on first window creation
  • Auto-pump — events are pumped at ~60fps (16ms interval) automatically
  • Auto-stop — the event pump stops when all windows are closed
import { NativeWindow } from "@fcannizzaro/native-window";

const win = new NativeWindow({
  title: "My App",
  width: 1024,
  height: 768,
  devtools: true,
});

Properties

id (readonly)

Unique numeric identifier for the window, assigned at construction time.

const win = new NativeWindow({ title: "My App" });
console.log(win.id); // e.g. 1

WindowOptions

All options are optional. Pass them to the NativeWindow constructor:

OptionTypeDefaultDescription
titlestring""Window title
widthnumber800Inner width in logical pixels
heightnumber600Inner height in logical pixels
xnumberX position in screen coordinates
ynumberY position in screen coordinates
minWidthnumberMinimum inner width
minHeightnumberMinimum inner height
maxWidthnumberMaximum inner width
maxHeightnumberMaximum inner height
resizablebooleantrueAllow window resizing
decorationsbooleantrueShow title bar and borders
transparentbooleanfalseTransparent window background
alwaysOnTopbooleanfalseFloat above other windows
visiblebooleantrueShow window immediately on creation
devtoolsbooleanfalseEnable browser devtools

Content Loading

loadUrl(url: string): void

Navigate the webview to a URL.

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

loadHtml(html: string): void

Load an HTML string directly into the webview.

win.loadHtml("<h1>Hello</h1>");

Security: Never interpolate unsanitized user input into HTML strings. Use a sanitization library such as DOMPurify or sanitize-html. See the Security guide for details.

unsafe.evaluateJs(script: string): void

Execute JavaScript in the webview context. This is fire-and-forget — there is no return value. Use postMessage/onMessage to send results back.

Grouped under the unsafe namespace to signal injection risk.

win.unsafe.evaluateJs('document.title = "Updated"');

Security: Never pass unsanitized user input directly. Use sanitizeForJs() to escape strings. See the Security guide for details.

postMessage(message: string): void

Send a string message to the webview. The message is delivered via the window.__native_message__ callback on the webview side.

win.postMessage("data from host");

Window Control

MethodDescription
setTitle(title: string)Set the window title
setSize(width: number, height: number)Set the window size in logical pixels
setMinSize(width: number, height: number)Set minimum window size
setMaxSize(width: number, height: number)Set maximum window size
setPosition(x: number, y: number)Set window position in screen coordinates
setResizable(resizable: boolean)Enable or disable window resizing
setDecorations(decorations: boolean)Show or hide title bar and borders
setAlwaysOnTop(alwaysOnTop: boolean)Toggle always-on-top mode

Window State

MethodDescription
show()Show the window
hide()Hide the window
close()Close and destroy the window
focus()Bring the window to focus
maximize()Maximize the window
minimize()Minimize the window
unmaximize()Restore the window from maximized state
reload()Reload the current page in the webview

Events

MethodCallback Signature
onMessage(cb)(message: string, sourceUrl: string) => void
onClose(cb)() => void
onResize(cb)(width: number, height: number) => void
onMove(cb)(x: number, y: number) => void
onFocus(cb)() => void
onBlur(cb)() => void
onPageLoad(cb)(event: "started" | "finished", url: string) => void
onTitleChanged(cb)(title: string) => void
onReload(cb)() => void

Example:

win.onPageLoad((event, url) => {
  if (event === "finished") {
    console.log("Page loaded:", url);
  }
});

win.onResize((width, height) => {
  console.log(`Window resized to ${width}x${height}`);
});

Utility Functions

sanitizeForJs

Escape a string for safe embedding inside a JavaScript string literal. Handles backslashes, quotes, newlines, null bytes, closing </script> tags, and Unicode line/paragraph separators.

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

const userInput = 'He said "hello"\n<script>alert(1)</script>';
win.unsafe.evaluateJs(`display("${sanitizeForJs(userInput)}")`);

checkRuntime(): RuntimeInfo

Check if the native webview runtime is available. Returns { available: boolean, version?: string, platform: "macos" | "windows" | "unsupported" }.

ensureRuntime(): RuntimeInfo

Check for the runtime and install it if missing (Windows only). Downloads the WebView2 Evergreen Bootstrapper (~2MB) from Microsoft and runs it silently. Throws on failure.

RuntimeInfo

Return type for checkRuntime() and ensureRuntime():

interface RuntimeInfo {
  available: boolean;
  version?: string;
  platform: "macos" | "windows" | "unsupported";
}

Legacy API

The following functions exist for backward compatibility but are not needed when using the NativeWindow class, which manages initialization and event pumping automatically:

FunctionDescription
init()Initialize the native window system manually
pumpEvents()Process pending native UI events manually
run(intervalMs?)Convenience: calls init() then starts a pumpEvents() interval. Returns a cleanup function. Deprecated.

Known Limitations

  • ~16ms event latency from the pumpEvents() polling interval
  • HTML null origin — content loaded via loadHtml() has a null CORS origin; use loadUrl() for fetch/XHR
  • No return values from unsafe.evaluateJs() — use postMessage/onMessage to send results back
  • 2 MB HTML limit on Windows when using loadHtml()
  • Use bun --watch instead of bun --hot for development (native addon reloading requires a process restart)

On this page