Robust cross-platform webview library for Node.js written in Rust. It is a native binding to tao and wry allowing you to easily manage cross platform windowing and webview.
Caution
This library is still in development and not ready for production use. Feel free to experiment with it and report any issues you find.
npm install @webviewjs/webview| Platform | Supported |
|---|---|
| x86_64-pc-windows-msvc | âś… |
| i686-pc-windows-msvc | âś… |
| aarch64-pc-windows-msvc | âś… |
| x86_64-apple-darwin | âś… |
| aarch64-apple-darwin | âś… |
| x86_64-unknown-linux-gnu | âś… |
| i686-unknown-linux-gnu | âś… |
| aarch64-unknown-linux-gnu | âś… |
| armv7-unknown-linux-gnueabihf | âś… |
| aarch64-linux-android | âś… |
| armv7-linux-androideabi | âś… |
| x86_64-unknown-freebsd | âś… |
import { Application } from '@webviewjs/webview';
// or
const { Application } = require('@webviewjs/webview');
const app = new Application();
const window = app.createBrowserWindow();
const webview = window.createWebview();
webview.loadUrl('https://nodejs.org');
app.run();WebviewJS provides a cross-platform menu system that works on macOS, Windows, and Linux.
import { Application, initMenuSystem } from '@webviewjs/webview';
// Initialize menu system (recommended, especially for macOS)
initMenuSystem();
const app = new Application();
// Set global application menu
app.setMenu({
items: [
{
label: "File",
submenu: {
items: [
{ id: "new", label: "New", accelerator: "CmdOrCtrl+N" },
{ id: "open", label: "Open", accelerator: "CmdOrCtrl+O" },
{ role: "separator" },
{ id: "quit", label: "Quit", accelerator: "CmdOrCtrl+Q" }
]
}
},
{
label: "Edit",
submenu: {
items: [
{ role: "copy" },
{ role: "paste" },
{ role: "cut" },
{ role: "selectall" }
]
}
}
]
});
const window = app.createBrowserWindow();
const webview = window.createWebview({ url: 'https://nodejs.org' });
app.run();import { Application, WebviewApplicationEvent } from '@webviewjs/webview';
const app = new Application();
// Handle menu events
app.bind((event) => {
if (event.event === WebviewApplicationEvent.CustomMenuClick) {
const menuEvent = event.customMenuEvent;
console.log(`Menu item clicked: ${menuEvent.id}`);
console.log(`From window: ${menuEvent.windowId}`);
// Handle specific menu items
switch (menuEvent.id) {
case 'new':
console.log('Creating new document...');
break;
case 'open':
console.log('Opening file...');
break;
case 'quit':
app.exit();
break;
}
}
});
// Set up menu...
app.setMenu({ /* ... */ });const app = new Application();
// Create window with custom menu
const window = app.createBrowserWindow({
title: "Custom Window",
menu: {
items: [
{
id: "window-action",
label: "Window Action",
accelerator: "Ctrl+W"
}
]
}
});
// Or check if window has a menu
if (window.hasMenu()) {
console.log('This window has a menu');
}id: Unique identifier for the menu item (used in events)label: Display text for the menu itemenabled: Whether the item is clickable (default: true)accelerator: Keyboard shortcut (e.g., "CmdOrCtrl+N", "Alt+F4")submenu: Nested menu itemsrole: Predefined menu items with built-in behavior
"copy": Standard copy action"paste": Standard paste action"cut": Standard cut action"selectall": Select all text action"separator": Visual separator line
const app = new Application();
const window = app.createBrowserWindow();
const webview = window.createWebview({
html: `<!DOCTYPE html>
<html>
<head>
<title>Webview</title>
</head>
<body>
<h1 id="output">Hello world!</h1>
<button id="btn">Click me!</button>
<script>
btn.onclick = function send() {
window.ipc.postMessage('Hello from webview');
}
</script>
</body>
</html>
`,
preload: `window.onIpcMessage = function(data) {
const output = document.getElementById('output');
output.innerText = \`Server Sent A Message: \${data}\`;
}`
});
if (!webview.isDevtoolsOpen()) webview.openDevtools();
webview.onIpcMessage((data) => {
const reply = `You sent ${data.body.toString('utf-8')}`;
window.evaluateScript(`onIpcMessage("${reply}")`)
})
app.run();You can close the application, windows, and webviews gracefully to ensure all resources (including temporary folders) are cleaned up properly.
const app = new Application();
const window = app.createBrowserWindow();
const webview = window.createWebview({ url: 'https://nodejs.org' });
// Set up event handler for close events
// You can use either onEvent() or bind() - they are equivalent
app.bind((event) => {
if (event.event === WebviewApplicationEvent.ApplicationCloseRequested) {
console.log('Application is closing, cleaning up resources...');
// Perform cleanup here: save data, close connections, etc.
}
if (event.event === WebviewApplicationEvent.WindowCloseRequested) {
console.log('Window close requested');
// Perform window-specific cleanup
}
});
// Close the application gracefully (cleans up temp folders)
app.exit();
// Or hide/show the window
window.hide(); // Hide the window
window.show(); // Show the window again
// Or reload the webview
webview.reload();For more details on closing applications and cleaning up resources, see the Closing Guide.
Check out examples directory for more examples:
- menu-system.mjs - Comprehensive menu system demonstration with all features
- window-menus.mjs - Window-specific vs global menu examples
- http/ - Serving content from a web server to webview
- transparent.mjs - Transparent window example
- close-example.mjs - Graceful application closing
Run any example with: node examples/menu-system.mjs (after building the project)
Warning
The CLI feature is very experimental and may not work as expected. Please report any issues you find.
You can use Single Executable Applications feature of Node.js to build an executable file. WebviewJS comes with a helper cli script to make this process easier.
webview --build --input ./path/to/your/script.js --output ./path/to/output-directory --name my-appYou can pass --resources ./my-resource.json to include additional resources in the executable. This resource can be imported using getAsset() or getRawAsset() functions from node:sea module.
bun installbun run build