Interactive Tables
Use SDK table primitives for sortable/resizable/reorderable tables instead of maintaining custom table mechanics per widget.
What The SDK Provides
InteractiveTable: shared table rendering with sticky headers and interaction chromeuseInteractiveTableState: sorting, order, width, drag bookkeepinghelpers:
fitColumnWidths,normalizeColumnOrder,normalizeColumnWidths,resolveColumnKeyStateChip: consistent enum-style chip rendering with optional brush integration
Real Pattern: Components Table Widget
ska-octopus-components-table-widget/src/components/ComponentsTable.tsx shows a production pattern:
Initializes
useInteractiveTableStatewith configured order/width/sortApplies responsive auto-fit widths when no saved widths are present
Sorts rows by selected column (including synthetic columns)
Uses
StateChipfor enum values
Persist User Table State
Pair table state callbacks with useWidgetConfigPersistence(instanceId):
const { persistConfig } = useWidgetConfigPersistence(instanceId);
const handleColumnOrderChange = (nextOrder: string[]) => {
persistConfig({ columnOrder: nextOrder });
};
const handleColumnWidthsChange = (nextWidths: Record<string, number>) => {
persistConfig({ columnWidths: nextWidths });
};
const handleSortChange = (next: { key: string; dir: "asc" | "desc" }) => {
persistConfig({ sortKey: next.key, sortDir: next.dir });
};
When To Use fitColumnWidths
Use fitColumnWidths or a project wrapper when:
Container width changes frequently
Visible columns are dynamic
You need deterministic first render widths
Recommendation
For any table heavy widget, start from the Components Table example and keep only domain specific data shaping in your widget.