How to Replace Plugin Widgets in React Compose SDK [Linux]
Summary: Micael Santana provides a detailed guide on replacing plugin widgets within embedded dashboards using the Compose SDK. The discussion includes steps to understand the process, create and register a custom widget component, and manage its lifecycle. Key points involve using the useExecuteCustomWidgetQuery hook to fetch data and the importance of registering custom widgets before the dashboard rendering. Unregistering widgets is also discussed, with a focus on optimal performance and preventing conflicts. The guide concludes with best practice recommendations for using custom widgets effectively within the Compose SDK.
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
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.