Solid Integration
Managed UI SolidJS components run inside the same generated UI DI container that React, Vue, and Svelte components use. The framework adapter is selected via a single project-wide flag in hexa-cli.config.json:
{
"ui": {
"framework": "solid",
"popup": { "mode": "managed", "sourceDir": "ui/popup", "indexFile": "index.html" }
}
}
When ui.framework: "solid" is set, HexaJS injects vite-plugin-solid into the popup/devtools/newtab build pipelines and emits content @View overlays that mount Solid components inside shadow DOM via SolidShadowRenderer from @hexajs-dev/ui/solid.
Solid support requires
solid-js@^1.8andvite-plugin-solid@^2.9. The framework choice is project-wide; mixing Solid with React, Vue, or Svelte per surface is not supported.
Request data in onMount
import { onMount, createSignal } from 'solid-js';
import { inject } from '@hexajs-dev/common';
import { HexaUIClient } from '@hexajs-dev/ui';
import { configApi } from './api';
import type { ConfigResponseMessage, GetConfigMessage } from './messages';
export default function ConfigPanel() {
const [config, setConfig] = createSignal<unknown | null>(null);
onMount(async () => {
const hexaUIClient = inject(HexaUIClient);
const response = await hexaUIClient.sendMessage<GetConfigMessage, ConfigResponseMessage>(
configApi.Get,
new GetConfigMessage(Date.now())
);
if (response && !hasHexaError(response) && response.config) {
setConfig(response.config);
}
});
return <pre>{config() ? JSON.stringify(config(), null, 2) : 'Loading...'}</pre>;
}
inject(...) here is the HexaJS DI helper from @hexajs-dev/common. Solid's createSignal is the reactive primitive — equivalent to Vue's ref or Svelte's $state.
Send changes from an event handler
import { inject } from '@hexajs-dev/common';
import { HexaUIClient } from '@hexajs-dev/ui';
import { configApi } from './api';
import type { ConfigResponseMessage, UpdateConfigMessage } from './messages';
async function setTheme(nextTheme: 'light' | 'dark'): Promise<void> {
const hexaUIClient = inject(HexaUIClient);
await hexaUIClient.sendMessage<UpdateConfigMessage, ConfigResponseMessage>(
configApi.Update,
new UpdateConfigMessage({ theme: nextTheme })
);
}
export default function ThemeToggle() {
return <button onClick={() => setTheme('dark')}>Dark mode</button>;
}
Resolve token values
import { HEXA_PLATFORM, inject } from '@hexajs-dev/common';
export default function PlatformBadge() {
const platform = inject(HEXA_PLATFORM);
return <span>{platform}</span>;
}
Shadow @View overlays
Solid components mounted inside a shadow DOM via @View receive the controller instance through the controller prop, exactly matching the React, Vue, and Svelte renderer contracts:
// sample-overlay.view.ts
import { HexaView, View } from '@hexajs-dev/core';
import SampleOverlayComponent from './sample-overlay.component';
import styles from './sample-overlay.css?inline';
@View({ id: 'sample', component: SampleOverlayComponent, styles, anchorSelector: 'body' })
export class SampleOverlayView extends HexaView {
count = 0;
increment = (): number => ++this.count;
}
// sample-overlay.component.tsx
import { createSignal } from 'solid-js';
import type { SampleOverlayView } from './sample-overlay.view';
export default function SampleOverlay(props: { controller: SampleOverlayView }) {
const [count, setCount] = createSignal(props.controller.count);
function tick() {
setCount(props.controller.increment());
}
return <button type="button" onClick={tick}>Count: {count()}</button>;
}
CSS isolation works identically to React — import your styles with ?inline and pass them as styles to the @View decorator. No special plugin options are needed since Solid does not auto-inject component CSS into <head>.
Important scope reminder
Managed UI Solid components resolve UI/general services and tokens. They do not resolve HexaBackgroundStore/HexaContentStore directly; ask the background through HexaUIClient messages and let state live in the appropriate context.
Classes
HexaUIClient
UI-context HexaClient. Sends messages from popup/devtools UI to the background.
import { HexaUIClient } from '@hexajs-dev/ui';
class HexaUIClient { ... }
Methods
sendMessage()
Send a message and await a response. Content → background uses runtime.sendMessage. Background → content requires a tabId — use BackgroundHexaClient.sendToTab().
sendMessage<TPayload, TResponse>(target: `${namespace}:${api}`, payload?: TPayload): Promise<TResponse>