Custom Panels
A custom panel replaces the entire content area of the UI (everything except the sidebar) with your own custom element, and gets its own item in the sidebar. This page documents the frontend side of the contract: how the frontend loads your code, which element it instantiates, and which properties it keeps in sync. Registering the panel itself happens on the core side and is covered by the backend documentation.
What the frontend receives
For a custom panel route, the panel info carries a _panel_custom configuration object:
interface CustomPanelConfig {
name: string;
embed_iframe: boolean;
trust_external: boolean;
js_url?: string;
module_url?: string;
html_url?: string;
}
Source selection and loading
module_urlis loaded as an ES module (recommended).js_urlis loaded as a classic script; each URL is only imported once per session.- If both are provided, the modern browser build loads
module_urland the legacy build loadsjs_url.
Your script must define a custom element. The frontend then creates:
- an element named exactly
config.name— e.g.name: my-panelmeanscustomElements.define("my-panel", ...); or - for legacy
html_urlpanels, an element namedha-panel-${name}.
External URL confirmation
If the panel URL's hostname is not localhost, 127.0.0.1, or the host currently serving the UI, and trust_external is not set, the user is asked to confirm before the code is loaded. Setting trust_external: true in the panel registration suppresses the prompt.
Properties your element receives
Once created, the panel element is kept up to date with these properties:
| Property | Description |
|---|---|
apex | The application state object (states, connection, user, service helpers). Reassigned on every state change. |
narrow | Boolean; true when the UI is in the narrow (mobile) layout. |
route | The current route object, so your panel can implement its own sub-routing. |
panel | The panel info object, including your _panel_custom config (useful for passing custom config to the panel). |
If your element defines a setProperties(props) method, the frontend calls it with the changed properties in a single batch; otherwise each property is assigned directly.
Iframe embedding
With embed_iframe: true, the panel runs inside a sandboxing <iframe> instead of the main document. The frontend writes a bootstrap document into the iframe and exposes the host element as window.customPanel for the bridge script. The same properties (apex, narrow, route, plus the panel config) are forwarded across the iframe boundary. Because navigation events fire on the main window, the host element exposes a navigate(path, options) function that embedded panels use to change the app's location from inside the iframe.
Styling
The panel container's background is set to var(--primary-background-color), and your element renders inside the normal theme scope, so all theme variables are available.