Flow Studio
Widget Rendering in WorkDesk
How the WidgetRenderer component loads and mounts a widget bundle inside the WorkDesk HIL inbox task view.
WidgetRenderer Component
// packages/flow-studio-api/src/clients/widgetApiClient.ts
// WidgetRenderer mounts the widget bundle into a sandbox iframe
interface WidgetRendererProps {
widgetId: string;
props: Record<string, unknown>;
executionId: string;
taskId: string;
onInteraction: (event: string, data: Record<string, unknown>) => void;
}
export function WidgetRenderer({ widgetId, props, executionId, onInteraction }: WidgetRendererProps) {
const { definition, loading } = useWidgetDefinition(widgetId);
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!definition || !containerRef.current) return;
loadWidgetBundle(definition.bundleUrl).then(() => {
const widget = window.BizFirstWidgets[widgetId];
widget.mount(containerRef.current!, props, {
onInteraction: (event, data) => onInteraction(event, data)
});
return () => widget.unmount(containerRef.current!);
});
}, [definition, widgetId]);
if (loading) return <WidgetSkeleton />;
return <div ref={containerRef} className="widget-container" />;
}
Bundle Loading Strategy
Widget bundles are loaded dynamically using a script tag injection strategy. Bundles are cached by the browser after first load — subsequent widget tasks for the same widget type load instantly.
const bundleCache = new Map<string, Promise<void>>();
function loadWidgetBundle(bundleUrl: string): Promise<void> {
if (bundleCache.has(bundleUrl)) return bundleCache.get(bundleUrl)!;
const promise = new Promise<void>((resolve, reject) => {
const script = document.createElement('script');
script.src = bundleUrl;
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load widget bundle: ${bundleUrl}`));
document.head.appendChild(script);
});
bundleCache.set(bundleUrl, promise);
return promise;
}
Sandbox Isolation
Widgets run in a sandboxed context to prevent them from accessing the parent page's DOM, cookies, or local storage. The sandbox policy is configured per widget definition and enforced via iframe sandbox attributes and Content Security Policy headers.