This article explains how to replace plugin widgets inside embedded dashboards that use Compose SDK. You’ll learn how the system works internally, registration functions, and how to override the default behavior of the registration. Step 1: Understand the goal When working with embedded dashboards that contain Custom Widget Plugins, for example: Histogram, Tabber etc. The default behavior of CSDK is show an error placeholder: The main idea of Custom Widgets is to replace them, so the CSDK renders it instead of the original widget inside the DashboardById component. Step 2: Custom Component To start you must create the component itself, to do it you should implement CustomWidgetComponent , and fetch widget data using the useExecuteCustomWidgetQuery hook. import { CustomWidgetComponent, useExecuteCustomWidgetQuery } from '@sisense/sdk-ui';
const ResultsTable: CustomWidgetComponent = (props) => {
const { data } = useExecuteCustomWidgetQuery(props);
if (!data) {
return null;
}
return (
<table style={{ margin: '20px' }}>
<thead>
<tr>
{data.columns.map((column, columnIndex) => (
<th key={columnIndex}>{column.name}</th>
))}
</tr>
</thead>
<tbody>
{data.rows.map((row, rowIndex) => (
<tr key={rowIndex}>
{row.map((cell, cellIndex) => (
<td key={cellIndex}>{cell.text}</td>
))}
</tr>
))}
</tbody>
</table>
);
}; What it does: The component itself it's just a component from React, so you implement: charts, simple tables etc. The key is the useExecuteCustomWidgetQuery that executes the widget query and returns structured data so your component can render however you want. Note: If you prefer working with raw query results instead of formatted data, you should use extractDimensionsAndMeasures together with useExecuteQuery . Step 3: The Data The CustomWidgetComponent receives properties similar to those by plugins internally, like: metadata, filters, configuration. This means: Some logic from plugin widgets can often be reused. Data remains compatible with Fusion. Migration from plugin widgets → Compose SDK is simplified Compose SDK mainly handles rendering, while configuration and data still come from the Sisense. Step 4: Register the custom widget After creating your component, you must register it before rendering the dashboard. Registration tells the SDK which component should be used when it encounters a Custom Widget Type. import {DashboardById,useCustomWidgets }from'@sisense/sdk-ui';
functionApp() {
const { registerCustomWidget }=useCustomWidgets();
registerCustomWidget('histogramwidget',ResultsTable);
return<DashboardByIddashboardOid={'66f4d4dd384428002ae0a21d'}/>;
} Important Registration must happen before the dashboard renders. Once registered, the widget is stored inside the main Compose SDK context. Any dashboard within that context will automatically use your custom widget. Step 5: Understand more about how it works internally Internally, the SDK keeps registered widgets inside a registry managed by the CSDK Context: So the rendering flow will be: Dashboard loads widget metadata. CSDK checks if that widget type exists in the registry: If registered → renders your custom component If not → renders the error placeholder The registry uses a key-value structure for fast lookup and to avoid repeated registrations. Step 6: Why widgets are designed to register only once Registration happens once per context lifecycle by design. This provides several benefits: Performance: prevents repeated registrations on re-renders Predictability: ensures only one implementation per widget type Stability: avoids conflicts between components trying to register the same widget Memory safety: prevents the registry from growing uncontrollably Since registrations are stored in a Context map, calling registerCustomWidget multiple times is unnecessary and discouraged. Step 7: How to unregister it? If you need to unregister a component, recently we added a new method named unregisterCustomWidget , to the CSDK Custom Widgets, that you can use to do it: Note: this was added in v2.26.0 , of Compose SDK. import { useCustomWidgets } from '@sisense/sdk-ui';
export const FunnelWidget = () => {
const { registerCustomWidget, unregisterCustomWidget } = useCustomWidgets();
const [type, setType] = useState<'funnel' | 'treemap'>('funnel');
const widget = type === 'funnel' ? CustomFunnel : CustomTreemap;
useEffect(() => {
registerCustomWidget('histogramwidget', widget);
return () => unregisterCustomWidget('histogramwidget');
}, [registerCustomWidget, unregisterCustomWidget, widget]);
return (
<div>
<Select
value={type}
onValueChange={(v) => setType(v as 'funnel' | 'treemap')}
>
<SelectTrigger className="w-[180px] my-3">
<SelectValue placeholder="Chart Type" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="funnel">Funnel</SelectItem>
<SelectItem value="treemap">Treemap</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<DashboardById
key={`dashboard-${type}`}
dashboardOid={'68dae1429e8028a69c6a41ee'}
/>
</div>
);
}; Using it you don't need to re-render the Sisense Main Context to change the register type, but you still need to re-render the Dashboard Component. Best practice recommendation Register custom widgets once during application initialization whenever possible. Only force a context remount if you specifically need dynamic registration behavior. Conclusion: Custom Widgets in Compose SDK provide a powerful way to replace plugin widgets while still using the original widget data. Understanding that registration is stored in a context-level registry explains: why widgets are registered once, why repeated registration isn’t needed and why remounting the context is sometimes required for advanced scenarios. References/Related Content Compose SDK documentation: DashboardById Component . Compose SDK documentation: Custom Widgets . Compose SDK documentation: Sinsense Context Provider . Mentioned Plugins: Tabber , Histogram . Disclaimer: This post outlines a potential custom workaround for a specific use case or provides instructions regarding a specific task. The solution may not work in all scenarios or Sisense versions, so we strongly recommend testing it in your environment before deployment. If you need further assistance with this, please let us know.