BrowserWindow API
Create and control browser windows
// in the main processimport { BrowserWindow } from "electrobun/bun";
const win = new BrowserWindow({ title: "my url window", frame: { width: 1800, height: 600, x: 2000, y: 2000, }, url: "views://mainview/index.html",});Constructor Options
title
Set the title of the window.
const win = new BrowserWindow({ title: "my url window",});frame
Set the window dimensions.
const win = new BrowserWindow({ frame: { width: 1800, height: 600, x: 2000, y: 2000, },});styleMask
This controls the OSX window appearance and functionality. You can set the following:
const win = new BrowserWindow({ title: "my url window", url: "views://mainview/index.html", frame: { width: 1800, height: 600, x: 2000, y: 2000, }, styleMask: { // These are the current defaults Borderless: false, Titled: true, Closable: true, Miniaturizable: true, Resizable: true, UnifiedTitleAndToolbar: false, FullScreen: false, FullSizeContentView: false, UtilityWindow: false, DocModalWindow: false, NonactivatingPanel: false, HUDWindow: false, }});titleBarStyle
Controls the window’s title bar appearance. This option works across all platforms (macOS, Windows, and Linux).
Available values:
"default"- Normal title bar with native window controls (close, minimize, maximize buttons)"hidden"- No title bar, no native window controls. Use this for fully custom window chrome where you implement your own title bar and window controls in HTML/CSS"hiddenInset"- Transparent title bar with inset native controls. On macOS, this shows the traffic light buttons overlaid on your content. On other platforms, this behaves similarly tohidden
// Default title barconst win = new BrowserWindow({ title: "Standard Window", url: "views://mainview/index.html", titleBarStyle: "default",});
// Hidden title bar for fully custom chromeconst customWin = new BrowserWindow({ title: "Custom Titlebar", url: "views://mainview/index.html", titleBarStyle: "hidden",});
// Hidden inset - transparent titlebar with traffic lights (macOS)const insetWin = new BrowserWindow({ title: "Inset Window", url: "views://mainview/index.html", titleBarStyle: "hiddenInset",});When using titleBarStyle: "hidden" or "hiddenInset", you’ll typically want to create a custom title bar in your HTML. See the Draggable Regions documentation for making your custom title bar draggable, and use the window control methods (close(), minimize(), maximize()) to implement custom window buttons.
activate
Controls whether the window should take focus when it is first shown. The default is true. Set activate: false for palette windows, tray popovers, or other UI that should open without stealing focus.
const palette = new BrowserWindow({ title: "Command Palette", url: "views://palette/index.html", frame: { width: 420, height: 520, x: 200, y: 120 }, activate: false,});trafficLightOffset
macOS-only. Offsets the native traffic light buttons when using titleBarStyle: "hiddenInset". This is ignored on Windows and Linux.
const win = new BrowserWindow({ title: "Inset Window", url: "views://mainview/index.html", titleBarStyle: "hiddenInset", trafficLightOffset: { x: 12, y: 10, },});transparent
When set to true, the window background becomes transparent, allowing you to create non-rectangular windows, floating widgets, or windows with rounded corners and drop shadows.
const floatingWidget = new BrowserWindow({ title: "Floating Widget", url: "views://widget/index.html", frame: { width: 300, height: 200, x: 100, y: 100 }, titleBarStyle: "hidden", transparent: true,});For transparency to work correctly, your HTML/CSS must also have a transparent background:
/* In your CSS */html, body { background: transparent;}
/* Create a visible floating card */.floating-card { background: rgba(30, 30, 50, 0.95); border-radius: 16px; backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);}sandbox
When set to true, the webview runs in sandbox mode. This disables RPC (remote procedure calls) and only allows event emission. Use sandbox mode for displaying untrusted content like remote URLs where you want to prevent malicious sites from accessing internal APIs.
// Sandboxed window for untrusted contentconst externalBrowser = new BrowserWindow({ title: "External Browser", url: "https://example.com", sandbox: true, // Disable RPC for security});
// Events still work in sandbox modeexternalBrowser.webview.on("dom-ready", () => { console.log("Page loaded");});
externalBrowser.webview.on("will-navigate", (event) => { console.log("Navigating to:", event.data.detail);});Security Model:
- Events work - Navigation events (
will-navigate,did-navigate,dom-ready, etc.) still fire normally - RPC is disabled - The
rpcoption is ignored; no function calls between browser and main process - No webview tags - Sandboxed webviews cannot create nested
<electrobun-webview>elements (OOPIFs) - Navigation controls work - You can still use
loadURL(),goBack(),goForward(), etc.
When to use sandbox mode
- Loading external/untrusted URLs (e.g., user-provided links, third-party content)
- Building a web browser or content viewer that displays arbitrary websites
- Embedding documentation or help content from external sources
- Any scenario where you want the webview isolated from your application’s internals
Using sandbox with <electrobun-webview> tag
You can also create sandboxed nested webviews using the sandbox attribute:
{/* In your HTML (within a trusted webview) */}<electrobun-webview src="https://untrusted-site.com" sandbox style="width: 100%; height: 500px;"></electrobun-webview>Info: The following options are used to instantiate the default BrowserView.
url
Set the initial url for the window’s default BrowserView to navigate to when it opens.
// Use any url on the internetconst win = new BrowserWindow({ url: "https://electrobun.dev",});
// or use the views:// url scheme to load local// content that you've bundled with your app.
const win = new BrowserWindow({ url: "views://mainview/index.html",});html
Set an html string for the window’s default BrowserView to load when it opens. Anything that would be valid in an html file including javascript and css can be used. Use this instead of setting the url property.
const htmlString = "<html><head></head><body><h1>hello world</h1></body></html>";
const win = new BrowserWindow({ html: htmlString,
});partition
Partitions allow you to separate the browser session. Things like cookies and so on. For example if you have two BrowserViews with the same partition and log into gmail in one, the other will also be logged into gmail. If you use two different partitions then you could log into a different gmail account in each BrowserView.
// ephemeral partition. If you close and reopen your app// even if you use the same partition name it will not// have persisted.const win = new BrowserWindow({ partition: "partition1",});
// To make partitions persistent just prefix it with `persist:`const win = new BrowserWindow({ partition: "persist:partition1",});preload
Set a preload script for the window’s default BrowserView to render after html is parsed but before any other javascript is executed. The preload script will be run after any navigation before the page’s scripts are run.
You can use either inline javascript or a url.
// Use any url on the internetconst win = new BrowserWindow({ preload: "https://electrobun.dev/some/remote/file.js",});
// or use the views:// preload scheme to load local// content that you've bundled with your app.
const win = new BrowserWindow({ preload: "views://somebundledview/preloadscript.js",});
// or use inline javascript
const win = new BrowserWindow({ preload: "document.body.innerHTML = 'Hello world'; console.log('hello console')",});rpc
The RPC property allows you to establish RPC (remote procedure calls) between the bun process and this window’s default BrowserView. In other words it lets you define functions that execute in the bun process that are callable and return a value back to the browser process and visa versa.
These RPC functions are asynchronous.
src/shared/types.ts
export type MyWebviewRPCType = { // functions that execute in the main process bun: RPCSchema<{ requests: { someBunFunction: { params: { a: number; b: number; }; response: number; }; }; messages: { logToBun: { msg: string; }; }; }>; // functions that execute in the browser context webview: RPCSchema<{ requests: { someWebviewFunction: { params: { a: number; b: number; }; response: number; }; }; messages: { logToWebview: { msg: string; }; }; }>;};src/bun/index.ts
import { BrowserWindow, BrowserView } from "electrobun/bun";import { type MyWebviewRPCType } from "../shared/types";
// Create an RPC object for the bun handlers with the shared typeconst myWebviewRPC = BrowserView.defineRPC<MyWebviewRPCType>({ maxRequestTime: 5000, handlers: { requests: { someBunFunction: ({ a, b }) => { console.log(`browser asked me to do math with: ${a} and ${b}`); return a + b; }, }, // When the browser sends a message we can handle it // in the main bun process messages: { "*": (messageName, payload) => { console.log("global message handler", messageName, payload); }, logToBun: ({ msg }) => { console.log("Log to bun: ", msg); }, }, },});
// Pass the RPC object to the BrowserWindow, which will set it// on the window's default BrowserViewconst win = new BrowserWindow({ title: "my window", url: "views://mainview/index.html", frame: { width: 1800, height: 600, x: 2000, y: 2000, }, rpc: myWebviewRPC,});
// ... later on
// Note: These RPC methods will inherit types from the shared type
// Call a browser function from bunconst answer = await win.webview.rpc.request.someWebviewFunction({ a: 4, b: 6 });
// Send a message to the BrowserView from bunwin.webview.rpc.send.logToWebview({ msg: "my message" });Info: The above code snippet shows defining the bun process rpc handlers and calling the browser process handlers from bun. To see how to handle the Browser context code take a look at the Electroview Class (Browser API).
Properties
webview
This is a getter for the window’s default BrowserView.
const win = new BrowserWindow({ ...});
const defaultWebview = win.webview;Methods
setTitle
Change the window title:
win.setTitle('new title')close
Close a window.
win.close();show / showInactive / activate / hide
Control window visibility and focus. show() shows and activates the window. showInactive() shows it without activating it. activate() focuses an already-visible window. hide() hides the window without closing it.
const win = new BrowserWindow({ title: "Palette", url: "views://palette/index.html", hidden: true, activate: false,});
// Reveal without stealing focuswin.showInactive();
// Later, explicitly bring it to the frontwin.activate();
// Hide without closingwin.hide();
// Show and activatewin.show();focus (deprecated)
focus() is a deprecated alias for activate(). Existing code still works, but prefer activate() in new code.
// Oldwin.focus();
// Newwin.activate();minimize / unminimize / isMinimized
Control and check the minimized state of a window.
// Minimize the windowwin.minimize();
// Restore from minimized statewin.unminimize();
// Check if window is minimizedif (win.isMinimized()) { console.log("Window is minimized");}maximize / unmaximize / isMaximized
Control and check the maximized state of a window. On macOS, this uses the “zoom” functionality which fills the screen while keeping the menu bar visible.
// Maximize the windowwin.maximize();
// Restore from maximized statewin.unmaximize();
// Check if window is maximizedif (win.isMaximized()) { console.log("Window is maximized");}setFullScreen / isFullScreen
Control and check the fullscreen state of a window. Fullscreen mode hides the title bar and dock/taskbar.
// Enter fullscreen modewin.setFullScreen(true);
// Exit fullscreen modewin.setFullScreen(false);
// Check if window is in fullscreenif (win.isFullScreen()) { console.log("Window is in fullscreen mode");}
// Toggle fullscreenwin.setFullScreen(!win.isFullScreen());setAlwaysOnTop / isAlwaysOnTop
Control and check whether a window stays above all other windows. Useful for floating tools, overlays, or picture-in-picture style windows.
// Make window always on topwin.setAlwaysOnTop(true);
// Disable always on topwin.setAlwaysOnTop(false);
// Check if window is always on topif (win.isAlwaysOnTop()) { console.log("Window is pinned above other windows");}
// Toggle always on topwin.setAlwaysOnTop(!win.isAlwaysOnTop());setPosition(x, y)
Move the window to a specific position on screen. Coordinates use a top-left origin (0, 0 is the top-left corner of the screen).
// Move window to position (200, 150)win.setPosition(200, 150);
// Center window on screen (approximate)const screenWidth = 1920; // Get actual screen dimensionsconst screenHeight = 1080;const frame = win.getFrame();win.setPosition( (screenWidth - frame.width) / 2, (screenHeight - frame.height) / 2);setSize(width, height)
Resize the window to specific dimensions. The window’s top-left corner position is preserved.
// Resize window to 800x600win.setSize(800, 600);
// Make window square based on current widthconst frame = win.getFrame();win.setSize(frame.width, frame.width);setFrame(x, y, width, height)
Set both position and size of the window in a single call. This is more efficient than calling setPosition and setSize separately when you need to change both.
// Move and resize window in one callwin.setFrame(100, 100, 1024, 768);
// Restore window to a saved position/sizeconst savedFrame = { x: 200, y: 150, width: 800, height: 600 };win.setFrame(savedFrame.x, savedFrame.y, savedFrame.width, savedFrame.height);setWindowButtonPosition(x, y)
macOS-only. Reposition the native traffic light buttons at runtime. This is most useful with titleBarStyle: "hiddenInset". On Windows and Linux the method is available but does nothing.
const win = new BrowserWindow({ title: "Inset Window", url: "views://mainview/index.html", titleBarStyle: "hiddenInset",});
win.setWindowButtonPosition(16, 12);getFrame()
Get the current position and size of the window. Returns an object with x, y, width, and height properties.
// Get current window frameconst frame = win.getFrame();console.log(`Position: (${frame.x}, ${frame.y})`);console.log(`Size: ${frame.width}x${frame.height}`);
// Save and restore window frameconst savedFrame = win.getFrame();// ... laterwin.setFrame(savedFrame.x, savedFrame.y, savedFrame.width, savedFrame.height);getPosition()
Get the current position of the window. Returns an object with x and y properties.
// Get current window positionconst pos = win.getPosition();console.log(`Window is at (${pos.x}, ${pos.y})`);
// Check if window is at originconst { x, y } = win.getPosition();if (x === 0 && y === 0) { console.log("Window is at origin");}getSize()
Get the current size of the window. Returns an object with width and height properties.
// Get current window sizeconst size = win.getSize();console.log(`Window is ${size.width}x${size.height}`);
// Check aspect ratioconst { width, height } = win.getSize();const aspectRatio = width / height;console.log(`Aspect ratio: ${aspectRatio.toFixed(2)}`);setVisibleOnAllWorkspaces / isVisibleOnAllWorkspaces
Control and check whether a window is visible on all virtual desktops/workspaces. This is useful for utility windows, floating tools, or widgets that should remain accessible across all spaces.
// Make window visible on all workspaceswin.setVisibleOnAllWorkspaces(true);
// Restrict to current workspacewin.setVisibleOnAllWorkspaces(false);
// Check if window is visible on all workspacesif (win.isVisibleOnAllWorkspaces()) { console.log("Window is visible on all workspaces");}setPageZoom / getPageZoom
Control and get the page zoom level for the window’s webview. A value of 1.0 represents 100% zoom.
// Set zoom to 150%win.setPageZoom(1.5);
// Get current zoom levelconst zoom = win.getPageZoom();console.log(`Current zoom: ${zoom * 100}%`);
// Reset to default zoomwin.setPageZoom(1.0);on(name, handler)
Subscribe to BrowserWindow events (see below).
Events
close
When a window closes. Per-window close handlers fire before global close handlers, ensuring your handlers run before the internal exitOnLastWindowClosed logic.
// listen to a specific window's close eventwin.on('close', (event) => { const {id} = event.data;
console.log('window closed')});
// listen globally to window close eventsimport Electrobun from 'electrobun/bun';
Electrobun.events.on('close', (event) => { const {id} = event.data;
if (win.id === id) { console.log('my window closed'); } else { console.log(`some other window with id ${id}` closed); }});resize
When a window’s width or height changes. This events sends the x and y as part of the data because a window may be resized by dragging the top-left corner which would also reposition it.
// listen to a specific window's resize eventwin.on("resize", (event) => { const { id, x, y, width, height } = event.data; console.log("window resized", id, x, y, width, height);});
// listen globally to window resize eventsimport Electrobun from 'electrobun/bun';
Electrobun.events.on("resize", (event) => { const { id, x, y, width, height } = event.data; console.log("window resized", id, x, y, width, height);});move
When a window’s position changes.
// listen to a specific window's move eventwin.on("move", (event) => { const { id, x, y } = event.data; console.log("window moved", id, x, y);});
// listen globally to window move eventsimport Electrobun from 'electrobun/bun';
Electrobun.events.on("move", (event) => { const { id, x, y } = event.data; console.log("window moved", id, x, y);});focus
When a window becomes the key window (receives focus). This is useful for tracking which window should receive keyboard shortcuts or other focus-dependent actions.
// listen to a specific window's focus eventwin.on("focus", (event) => { const { id } = event.data; console.log("window focused", id);});
// listen globally to window focus eventsimport Electrobun from 'electrobun/bun';
Electrobun.events.on("focus", (event) => { const { id } = event.data; console.log("window focused", id);});blur
When a window loses focus (is no longer the key window).
// listen to a specific window's blur eventwin.on("blur", (event) => { const { id } = event.data; console.log("window lost focus", id);});
// listen globally to window blur eventsimport Electrobun from 'electrobun/bun';
Electrobun.events.on("blur", (event) => { const { id } = event.data; console.log("window lost focus", id);});