Skip to content

UI Tag (<electrobun-ui>)

<electrobun-ui> puts a GPU-rendered, reactive UI layer on top of web content. The custom element is only an anchor: it reserves space in the page, Electrobun’s native compositor places a Dawn view over it (exactly like <electrobun-wgpu>), and the trusted main process renders a UI tree into that view.

Use it when a webview-based app needs chrome the page shouldn’t own — overlays, HUDs, privileged controls — without giving the page access to them.

In the page

<electrobun-ui name="inspector"></electrobun-ui>

The element behaves like a block element; size and position it with CSS. The overlay tracks the element through scrolling and layout changes. The name attribute selects which registered UI root mounts here.

In the main process

import { live, signal, registerUIRoot } from "electrobun/main/ui";
const registration = registerUIRoot("inspector", { background: "#1b1b28" }, () => {
const [clicks, setClicks] = signal(0);
return (
<column grow={1} pad={12} gap={8} justify="center" align="center">
<text size={18} color="#e4e4f0">{live(() => `clicks: ${clicks()}`)}</text>
<box pad={8} radius={6} bg="#232336" onClick={() => setClicks((c) => c + 1)}>
<text size={12} color="#e4e4f0">Click me</text>
</box>
</column>
);
});
// later: registration.dispose()

Every <electrobun-ui name="inspector"> instance — across webviews and windows — gets its own tree (the builder runs per mount). When the element is removed from the DOM, its native view and reactive scope are disposed.

Notes

  • The UI tree runs in the main process with full privileges; the page can position the anchor but cannot reach into the overlay.
  • Pointer input works over the overlay; keyboard events go to the host window, so window-level onKey handlers apply.
  • Under the hood this is createUIView mounted into the tag’s WGPUView — you can use that API directly for views you create yourself.