Design Panel
The design panel lets users customize your widget's appearance at design time. It appears in the Fusion widget editor sidebar and controls the styleOptions passed to your visualization component.
Design Panel Component
A design panel implements DesignPanelProps — it receives the current style options and an onChange callback:
import type { DesignPanelProps } from '@sisense/sdk-ui';
interface MyStyleOptions {
colorScheme: 'warm' | 'cool' | 'monochrome';
showLegend: boolean;
}
// Wrap in React.memo to avoid unnecessary re-renders.
// Set displayName so the component is identifiable in React DevTools.
const MyDesignPanel: React.FC<DesignPanelProps<MyStyleOptions>> = React.memo(
({ styleOptions, onChange }) => {
// The update helper reduces repetition: spreads styleOptions and sets one key.
const update = <K extends keyof MyStyleOptions>(key: K, value: MyStyleOptions[K]) =>
onChange({ ...styleOptions, [key]: value });
return (
<div>
<label>
Color Scheme
<select
value={styleOptions.colorScheme ?? 'warm'}
onChange={(e) => update('colorScheme', e.target.value as MyStyleOptions['colorScheme'])}
>
<option value="warm">Warm</option>
<option value="cool">Cool</option>
<option value="monochrome">Monochrome</option>
</select>
</label>
</div>
);
},
);
MyDesignPanel.displayName = 'MyDesignPanel';
Important: Always spread the existing styleOptions when calling onChange to preserve other properties:
// Correct — preserves other properties
onChange({ ...styleOptions, showLegend: false });
// Wrong — overwrites everything
onChange({ showLegend: false });
Registering the Design Panel
Include it in your plugin declaration. The DesignPanel type alias describes the accepted component shape:
const plugin: WidgetPlugin<VisualizationProps> = {
name: 'my-custom-chart',
version: '1.0.0',
requiredApiVersion: '^2.27.0',
pluginType: 'widget',
customWidget: {
name: 'my-custom-chart',
displayName: 'My Custom Chart',
visualization: { Component: Visualization },
designPanel: {
Component: MyDesignPanel,
},
dataPanel: { ... },
},
};
If your widget doesn't need style customization, omit the designPanel field entirely.
Organizing Sections
For complex design panels, split into focused section components:
// sections/ColorSection.tsx
export const ColorSection: React.FC<{
value: string;
onChange: (value: string) => void;
}> = ({ value, onChange }) => (
<div>
<h4>Colors</h4>
<select value={value} onChange={(e) => onChange(e.target.value)}>
<option value="warm">Warm</option>
<option value="cool">Cool</option>
</select>
</div>
);
// DesignPanels.tsx
import { ColorSection } from './sections/ColorSection';
export const DesignPanels: React.FC<DesignPanelProps<MyStyleOptions>> = ({
styleOptions,
onChange,
}) => (
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
<ColorSection
value={styleOptions.colorScheme ?? 'warm'}
onChange={(colorScheme) => onChange({ ...styleOptions, colorScheme })}
/>
</div>
);
Best Practices
Define defaults — Always provide sensible defaults in your visualization component so it renders correctly even with an empty
styleOptions.Use
Pickfor SDK style types — If wrapping a built-in chart, pick only the properties your design panel controls:import type { LineStyleOptions } from '@sisense/sdk-ui'; interface MyStyleOptions extends Pick<LineStyleOptions, 'subtype' | 'legend' | 'markers'> {}Keep types serializable — Style options are persisted as JSON. Avoid functions, class instances, Dates, or
undefinedin nested objects.Use
React.memoanddisplayName— Wrap your design panel to avoid unnecessary re-renders and setdisplayNamefor React DevTools.
Use any CSS approach for styling your design panel (CSS modules, Emotion, Tailwind, inline styles).
Using an AI Agent
Your AI agent automates the boilerplate of wiring a new style option through all three locations (the type, the visualization default, and the panel control). Tell it what you want in plain language:
- "Add a style option for bar color" — adds the field to
StyleOptionsinsrc/types.ts, adds a safe default inVisualization.tsx, and writes the matching control inDesignPanel.tsx(select, checkbox, number input, or color picker depending on the field type) - "Add a number format selector" — adds
NumberFormatConfigtoStyleOptions, injects it into measure columns viauseMemosoformatDataSet(data, dataOptions)applies formatting after the query, and adds a dropdown with common presets (Auto, Integer, 2 decimals, Percentage, Currency) toDesignPanel.tsx
Next lesson: Event Handling and Cross-Filtering