Skip to main content

Widget registry

The widget registry is the single source of truth for which widgets exist and how they mount. The canvas persists only a widget's type (plus layout and config); at render time it looks the type up here and mounts the matching component.

Source: src/widgets/registry.tsx

WidgetRenderProps

Every registered component receives these props from the canvas:

interface WidgetRenderProps {
/** Per-instance config saved on the view; falls back to sample data. */
config?: Record<string, unknown>;
/** Widget instance id, used to route cross-widget actions. */
widgetId?: string;
}

WidgetDefinition

interface WidgetDefinition {
type: string; // stable registry key
displayName: string;
description?: string;
category: WidgetCategory; // tab grouping in the widget picker
icon: LucideIcon; // icon shown in the picker
defaultSize: { w: number; h: number }; // initial grid units
defaultConfig?: Record<string, unknown>; // seed for fresh instances
dataless?: boolean; // hide drawer "Data" section
hideActions?: boolean; // hide drawer "Actions" section
component: React.ComponentType<WidgetRenderProps>;
}

The widget picker is a tabbed dialog: one tab per WidgetCategory, each listing its widgets as cards with the definition's icon. Categories render in WIDGET_CATEGORIES order; empty categories are skipped.

type WidgetCategory =
| "Maps & GIS"
| "Data & Charts"
| "AI & Imagery"
| "Media & Tools";

// Tab order in the picker.
export const WIDGET_CATEGORIES: WidgetCategory[];

Registry API

// The master list of all widgets.
export const WIDGET_DEFINITIONS: WidgetDefinition[];

// Look up one definition by its type key.
export function getWidgetDefinition(type: string): WidgetDefinition | undefined;

// List all definitions.
export function listWidgetDefinitions(): WidgetDefinition[];

// Definitions grouped by category (in WIDGET_CATEGORIES order, empties
// omitted); used by the picker's tabs.
export function listWidgetCategories(): {
category: WidgetCategory;
widgets: WidgetDefinition[];
}[];

getWidgetDefinition is backed by a Map built from WIDGET_DEFINITIONS, so lookups during render are constant-time.

Widgets have no fixed minimum size: tiles can be resized down to a single grid cell via the dividers between them. defaultSize only seeds the initial footprint when a widget is added from the picker; once placed, a tile's size is driven by the view's layout tree (see Workspaces & views).

Config-panel registry

Type-specific config UIs live in a parallel registry in src/widgets/config.tsx:

interface WidgetConfigPanelProps {
widgetId: string;
config: Record<string, unknown> | undefined;
updateConfig: (patch: Record<string, unknown>) => void;
section: "data" | "appearance";
siblings: WidgetInstance[];
}

type WidgetConfigPanel = React.ComponentType<WidgetConfigPanelProps>;

export function getWidgetConfigPanel(
type: string,
): WidgetConfigPanel | undefined;
export function getWidgetSectionDescription(
type: string,
section: WidgetDrawerSection,
): string;

Widgets without a registered panel still render the shared title field and any applicable default drawer sections.

Registered widgets

TypeDisplay nameCategoryFlags
arcgis-mapArcGIS MapMaps & GISdefaultConfig: { webMapId: "" }
arcgis-scene3D SceneMaps & GISdefaultConfig: { webSceneId: "" }
arcgis-legendLegendMaps & GISdefaultConfig: { sourceWidgetId: "" }
arcgis-link-chartLink ChartMaps & GISdefaultConfig: { serviceUrl: "" }
detailsDetailsMaps & GIShideActions, defaultConfig: { sourceWidgetId: "" }
table-cardTableData & Charts
listListData & ChartsdefaultConfig: { featureServiceId: "" }
indicatorIndicatorData & ChartsdefaultConfig: { featureServiceId: "" }
gantt-chartGantt ChartData & Chartsdataless
stock-priceStock TrackerData & ChartshideActions
tile-searchTile SearchAI & ImageryhideActions, defaultConfig: { sourceWidgetId: "", datasetId: "" }
ai-chatAI ChatAI & Imagerydataless
ai-agentsAI AgentsAI & Imagerydataless
world-clockWorld ClockMedia & Toolsdataless
audio-playerAudio PlayerMedia & ToolshideActions, defaultConfig: { audioUrl: "" }
weatherWeatherMedia & ToolshideActions

For a detailed guide to each widget's configuration, data source, and actions, see the Widget catalog.

Internal helpers

A few internals support data-driven widgets (src/widgets/internal/):

ModulePurpose
MapViewRegistryShares a live ArcGIS MapView between sibling widgets (Map ↔ Legend).
WidgetPlaceholderThe "configure me" placeholder for unconfigured data widgets.
WidgetShellThe header + content frame used while rendering.
SettingsGroupReusable form building blocks for config panels.

To add a widget, follow Creating a widget.