| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Note
This project is in beta. APIs may change without notice and some features may be incomplete or unstable.
Native OS webviews for Bun, Deno & Node.js. Create real desktop windows with embedded web content using wry + tao — providing WebKit on macOS and Linux, and WebView2 on Windows.
| Package | Description |
|---|---|
| @nativewindow/webview | Rust napi-rs addon providing native window + webview APIs |
| @nativewindow/ipc | Pure TypeScript typesafe IPC channel layer |
| @nativewindow/react | React bindings for the typed IPC layer |
| @nativewindow/tsdb | TanStack DB collection adapter for native-window IPC |
import { NativeWindow } from "native-window";
const win = new NativeWindow({
title: "My App",
width: 800,
height: 600,
});
win.loadHtml(`
<h1>Hello from native webview!</h1>
<button onclick="window.ipc.postMessage('clicked')">Click me</button>
`);
win.onMessage((msg) => {
console.log("From webview:", msg);
win.postMessage(`Echo: ${msg}`);
});
win.onClose(() => {
process.exit(0);
});Use native-window-ipc for compile-time checked messaging between Bun/Deno/Node and the webview. Schemas provide both types and runtime validation.
import { z } from "zod";
import { createWindow } from "@nativewindow/ipc";
const ch = createWindow(
{ title: "Typed IPC" },
{
schemas: {
// host -> webview
host: {
"update-title": z.string(),
},
// webview -> host
client: {
"user-click": z.object({ x: z.number(), y: z.number() }),
counter: z.number(),
},
},
},
);
// Receive typed messages from the webview (client events)
ch.on("user-click", (pos) => {
// pos: { x: number; y: number }
console.log(`Click at ${pos.x}, ${pos.y}`);
});
ch.on("counter", (n) => {
// n: number
ch.send("update-title", `Count: ${n}`);
});
// ch.send("counter", "wrong"); // Type error: "counter" is a client event
// ch.send("typo", 123); // Type error: "typo" does not exist
ch.window.loadHtml(`<html>...</html>`);The __channel__ object is auto-injected by createWindow / createChannel:
<script>
__channel__.send("user-click", { x: 10, y: 20 });
__channel__.on("update-title", (title) => {
document.title = title;
});
</script>For webview apps bundled with their own build step, import the client directly:
import { z } from "zod";
import { createChannelClient } from "@nativewindow/ipc/client";
const ch = createChannelClient({
schemas: {
host: {
"update-title": z.string(),
},
client: {
counter: z.number(),
},
},
});
// Send client events to the host
ch.send("counter", 42); // Typed!
// Receive host events from the host
ch.on("update-title", (t) => {
// t: string
document.title = t;
});On Windows 10, the WebView2 runtime may not be installed. Use checkRuntime() to detect it and ensureRuntime() to auto-install if missing.
import { checkRuntime, ensureRuntime } from "native-window";
const info = checkRuntime();
console.log(info);
// { available: true, version: "128.0.2739.42", platform: "windows" }
// { available: false, version: undefined, platform: "windows" }
// { available: true, version: undefined, platform: "macos" }
// { available: true, version: undefined, platform: "linux" }
if (!info.available) {
console.log("WebView2 not found, installing...");
const result = ensureRuntime(); // downloads ~2MB bootstrapper, runs silently
console.log("Installed:", result.version);
}On macOS, both functions return { available: true } immediately — WKWebView is a system framework. On Linux, both functions also return { available: true } — WebKitGTK is assumed to be installed. On Windows 11, WebView2 is pre-installed.
Check if the native webview runtime is available. Returns { available: boolean, version?: string, platform: "macos" | "windows" | "linux" | "unsupported" }.
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.
Create a native window with an embedded webview.
WindowOptions:
| Option | Type | Default | Description |
|---|---|---|---|
| title | string | "" | Window title |
| width | number | 800 | Inner width (logical pixels) |
| height | number | 600 | Inner height (logical pixels) |
| x | number | — | X position |
| y | number | — | Y position |
| minWidth / minHeight | number | — | Minimum size |
| maxWidth / maxHeight | number | — | Maximum size |
| resizable | boolean | true | Allow resizing |
| decorations | boolean | true | Show title bar and borders |
| transparent | boolean | false | Transparent background |
| alwaysOnTop | boolean | false | Float above other windows |
| visible | boolean | true | Initially visible |
| devtools | boolean | false | Enable devtools |
Content methods:
| Method | Description |
|---|---|
| loadUrl(url) | Navigate to a URL |
| loadHtml(html) | Load an HTML string |
| unsafe.evaluateJs(script) | Execute JS in the webview (fire-and-forget) |
| postMessage(msg) | Send a string to the webview via window.__native_message__ |
Window control:
| Method | Description |
|---|---|
| setTitle(title) | Set the window title |
| setSize(w, h) | Set the window size |
| setMinSize(w, h) / setMaxSize(w, h) | Set size constraints |
| setPosition(x, y) | Set window position |
| setResizable(bool) | Toggle resizability |
| setDecorations(bool) | Toggle decorations |
| setAlwaysOnTop(bool) | Toggle always-on-top |
| show() / hide() | Show or hide the window |
| close() | Close and destroy the window |
| focus() | Bring the window to focus |
| maximize() / minimize() / unmaximize() | Window state |
Events:
| Method | Callback signature |
|---|---|
| onMessage(cb) | (message: string) => void |
| onClose(cb) | () => void |
| onResize(cb) | (width: number, height: number) => void |
| onMove(cb) | (x: number, y: number) => void |
| onFocus(cb) / onBlur(cb) | () => void |
| onPageLoad(cb) | (event: "started" | "finished", url: string) => void |
| onTitleChanged(cb) | (title: string) => void |
Wrap an existing NativeWindow with a typed message channel. Schemas are required. Auto-injects the webview client script (disable with { injectClient: false }).
Convenience: creates a NativeWindow and wraps it with createChannel.
Returns the webview-side client as a self-contained JS string for manual injection.
Create a typed channel client inside the webview. Schemas are required. For use in bundled webview apps.
interface TypedChannel<T extends EventMap> {
send<K extends keyof T & string>(type: K, payload: T[K]): void;
on<K extends keyof T & string>(type: K, handler: (payload: T[K]) => void): void;
off<K extends keyof T & string>(type: K, handler: (payload: T[K]) => void): void;
}All security hardening is compiled in by default on all supported platforms — no build-time feature flags required.
See the Security documentation for the full threat model and best practices.
bun install
# or
deno installcd packages/webview
bun run build # release build
bun run build:debug # debug buildThe build targets the current platform. Cross-compilation targets are configured in packages/webview/package.json under napi.triples.
# Raw IPC example
bun samples/basic.ts
# Typed IPC example
bun samples/typed-ipc.ts# Run the IPC channel tests
cd packages/ipc
bun testMIT
| Back | FazBrowse Home | New Git URL |