Custom sandbox views and themes
Use ui to display custom HTML/CSS in your own sandbox when declarative forms are insufficient. There is one visible custom view per plugin.
Create a view
Section titled “Create a view”This api-example builds DOM only inside the plugin frame. The lifecycle cleanup array must be drained from stop.
const main = document.createElement("main");const title = document.createElement("h1");title.textContent = "My plugin";const note = document.createElement("p");note.textContent = "This interface lives in the plugin sandbox.";main.append(title, note);document.body.append(main);const style = document.createElement("style");style.textContent = "body { padding: 24px; background: var(--background-primary, #202127); color: var(--text-normal, #eee); font: 16px system-ui; }";document.head.append(style);const applyTheme = (tokens: Record<string, string>) => { for (const [name, value] of Object.entries(tokens)) { document.documentElement.style.setProperty(name, value); }};applyTheme(await api.ui.theme());cleanup.push(() => { main.remove(); style.remove();});cleanup.push(await api.ui.onThemeChange(applyTheme));cleanup.push(await api.ui.openView({ title: "My plugin", kind: "dialog" }));For persistent presentation choose kind panel. Escape, the host Close button, or the returned disposer dismisses the view. Reopening uses the same instance and frame.
Theme contract
Section titled “Theme contract”ui.theme and ui.onThemeChange expose an allowlist of CSS custom properties: background-primary, background-secondary, background-secondary-alt, background-floating, text-normal, text-muted, interactive-normal, brand-500, brand-600, font-primary, input-background, input-border, and background-modifier-accent, each prefixed by two hyphens.
An empty value means unavailable. Provide CSS fallbacks. Parent stylesheets and DOM objects are not exposed.
Assets and accessibility
Section titled “Assets and accessibility”Use addEventListener for handlers; remote scripts and inline event attributes are blocked. Bundled raster data URLs are allowed. Remote images must use images.load followed by images.url.
Use labels, real buttons, visible focus, responsive layouts, and reduced-motion styles. Test light and dark Fluxer themes and small windows. Remove listeners and DOM during stop, and guard asynchronous completions after shutdown.
