eythaann/Seelen-UI · error · Error
Root element not found
Error message
Root element not found
What it means
getRootContainer() looks up the DOM element with id 'root' and returns it as the mount point for React apps in Seelen UI webviews. If no #root element exists at call time the app has no mount point, so it throws instead of returning null.
Source
Thrown at libs/ui/react/utils/index.ts:6
import type { ResourceText } from "@seelen-ui/lib/types";
export function getRootContainer(): HTMLElement {
const element = document.getElementById("root");
if (!element) {
throw new Error("Root element not found");
}
return element;
}
export function toPhysicalPixels(size: number): number {
return Math.round(size * globalThis.devicePixelRatio);
}
export function getResourceText(text: ResourceText, locale: string): string {
if (typeof text === "string") {
return text;
}
return text[locale] || text["en"] || "Unknown";
}
// Difference between Windows epoch (1601) and Unix epoch (1970) in milliseconds
const EPOCH_DIFF_MILLISECONDS = 11644473600000n;
View on GitHub (pinned to dee4aaa940)
Solutions
- Add <div id="root"></div> to the webview's index.html body.
- Call getRootContainer() after DOM ready (script at end of body, defer, or DOMContentLoaded).
- Match the id used by your entry point with the one in the HTML.
- In tests, create a #root fixture or render into a container you create yourself.
Example fix
// before: <body><script src="index.js"></script></body> (no mount point) // after: <body><div id="root"></div><script src="index.js" defer></script></body>
Defensive patterns
Strategy: fallback
Validate before calling
const el = document.getElementById('root'); if (!el) throw new Error('#root missing - check index.html and script load order'); Type guard
function hasRoot(): boolean { return typeof document !== 'undefined' && document.getElementById('root') !== null; } Try / catch
let container: HTMLElement; try { container = getRootContainer(); } catch (e) { if (e instanceof Error && e.message === 'Root element not found') { container = document.createElement('div'); container.id = 'root'; document.body.appendChild(container); } else { throw e; } } Prevention
- Keep <div id="root"></div> in every widget index.html.
- Load entry scripts with defer or at end of body so the DOM exists.
- Call getRootContainer() inside DOMContentLoaded or after mount-ready signals.
- In tests, create the #root fixture before importing app entry modules.
When it happens
Trigger: Calling getRootContainer() before the DOM is parsed (script in <head> without defer, or before DOMContentLoaded); the HTML entry missing <div id="root"></div>; the element having a different id; calling from a context without document (tests/workers).
Common situations: Renaming the mount div during an HTML refactor; copying a template whose script runs before body exists; scaffolding with no root div; jsdom tests rendering the app without fixture markup.
Related errors
- LazySignal was not initialized
- Widget definition not found for ${currentWidgetId}
- Missing webview label
- Invalid widget id
- Monitor settings not initialized ${device.id}
AI-assisted analysis of eythaann/Seelen-UI@dee4aaa940 (2026-09-03).
Data as JSON: /api/errors/fd13fc0fd581a7b2.
Report an issue: GitHub.