Use this file to discover all available pages before exploring further.
A single Application instance can own as many BrowserWindow objects as you need. Each window has its own webview, title bar, and OS chrome, but they all share the same JavaScript event loop driven by app.run(). Because JavaScript is single-threaded, you do not need locks or inter-process messaging to share state between windows — any object reachable from your Node module is available to every window’s event handlers simultaneously.
Create each window by calling app.createBrowserWindow() and attach a webview with win.createWebview(). Both windows run as soon as app.run() is called.
JavaScript’s garbage collector may reclaim window objects that are no longer referenced. Keep a Map or array of all live window/webview pairs so they remain reachable.
import { Application } from '@webviewjs/webview';const app = new Application();const windows = new Map(); // id → { win, webview }function openWindow(id, url) { // Reuse an existing window instead of creating a duplicate if (windows.has(id)) { windows.get(id).win.show(); windows.get(id).win.focus(); return windows.get(id); } const win = app.createBrowserWindow({ title: id, width: 900, height: 600 }); const webview = win.createWebview({ url }); windows.set(id, { win, webview }); return { win, webview };}openWindow('main', 'app://localhost/');openWindow('editor', 'app://localhost/editor');openWindow('preview', 'app://localhost/preview');app.run();
app.createChildBrowserWindow() creates a window that is logically and visually attached to a parent. Child windows are ideal for dialogs, palettes, floating tool panels, and inspector drawers. They use the same BrowserWindowOptions as regular windows.
import { Application } from '@webviewjs/webview';const app = new Application();const mainWin = app.createBrowserWindow({ title: 'Main Window', width: 1200, height: 800,});mainWin.createWebview({ url: 'app://localhost/' });// Open a child window for "Find and Replace"function openFindReplace() { const child = app.createChildBrowserWindow({ title: 'Find & Replace', width: 480, height: 280, }); child.createWebview({ url: 'app://localhost/find-replace' }); return child;}app.on('custom-menu-click', ({ customMenuEvent }) => { if (customMenuEvent.id === 'find') { openFindReplace(); }});app.run();
Use createChildBrowserWindow for transient, dependent UI. Use createBrowserWindow for independent top-level windows that can outlive their siblings.
Call win.dispose() to destroy a window and release its native resources. After disposal, all method calls on that instance throw. Use win.isDisposed() to check. The using declaration (via Symbol.dispose) works if your runtime supports it.
Manual dispose
Symbol.dispose (using)
function closeWindow(id) { const entry = windows.get(id); if (!entry) return; entry.webview.dispose(); entry.win.dispose(); windows.delete(id);}
{ using win = app.createBrowserWindow({ title: 'Temp' }); using webview = win.createWebview({ html: '<p>Temporary</p>' }); // ... do work ...}// win and webview are automatically disposed when the block exits
Disposing a window while it is visible will close it immediately without any OS close-confirmation dialog. Always save user state before calling dispose().
When the user clicks the OS close button, WebviewJS hides the window rather than destroying it. This lets you reuse the window later without recreating it.
// Toggle a window's visibilityfunction toggleWindow(win) { if (win.isVisible()) { win.hide(); } else { win.show(); win.focus(); }}// Show all windowsfor (const { win } of windows.values()) { win.show();}
window-close-requested fires when any one window is hidden by the user. The event payload does not currently identify which window was hidden — use win.isVisible() on tracked windows to find out.
app.on('window-close-requested', () => { // One window was hidden. Update any window-list UI here. const visible = [...windows.values()].filter(({ win }) => win.isVisible()); console.log(`${visible.length} window(s) still visible`);});
2
Detect when the last window is closed
application-close-requested fires when all tracked windows have been hidden. This is the normal exit point.
app.on('application-close-requested', () => { // All windows are hidden — safe to exit app.exit();});
3
Prevent accidental exit
If you have unsaved work, show a confirmation dialog before exiting instead of calling app.exit() immediately.
app.on('application-close-requested', () => { if (hasUnsavedChanges()) { const paths = mainWin.openFileDialog({ title: 'Save before quitting?' }); if (paths.length) { saveFile(paths[0]).then(() => app.exit()); } // If the user cancels the dialog, the app stays open } else { app.exit(); }});
In some scenarios — for example a Node.js script that launches two completely separate windows with no shared state — you can create two Application instances and await Promise.all([app1.run(), app2.run()]). Each application drives its own event loop independently.
import { Application } from '@webviewjs/webview';const app1 = new Application();app1.createBrowserWindow().createWebview({ url: 'https://nodejs.org' });const app2 = new Application();app2.createBrowserWindow().createWebview({ url: 'https://wikipedia.org' });await Promise.all([app1.run(), app2.run()]);
This pattern is unusual — prefer a single Application with multiple windows when the windows need to share data or respond to the same menu events.