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
| Type | Display name | Category | Flags |
|---|---|---|---|
arcgis-map | ArcGIS Map | Maps & GIS | defaultConfig: { webMapId: "" } |
arcgis-scene | 3D Scene | Maps & GIS | defaultConfig: { webSceneId: "" } |
arcgis-legend | Legend | Maps & GIS | defaultConfig: { sourceWidgetId: "" } |
arcgis-link-chart | Link Chart | Maps & GIS | defaultConfig: { serviceUrl: "" } |
details | Details | Maps & GIS | hideActions, defaultConfig: { sourceWidgetId: "" } |
table-card | Table | Data & Charts | — |
list | List | Data & Charts | defaultConfig: { featureServiceId: "" } |
indicator | Indicator | Data & Charts | defaultConfig: { featureServiceId: "" } |
gantt-chart | Gantt Chart | Data & Charts | dataless |
stock-price | Stock Tracker | Data & Charts | hideActions |
tile-search | Tile Search | AI & Imagery | hideActions, defaultConfig: { sourceWidgetId: "", datasetId: "" } |
ai-chat | AI Chat | AI & Imagery | dataless |
ai-agents | AI Agents | AI & Imagery | dataless |
world-clock | World Clock | Media & Tools | dataless |
audio-player | Audio Player | Media & Tools | hideActions, defaultConfig: { audioUrl: "" } |
weather | Weather | Media & Tools | hideActions |
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/):
| Module | Purpose |
|---|---|
MapViewRegistry | Shares a live ArcGIS MapView between sibling widgets (Map ↔ Legend). |
WidgetPlaceholder | The "configure me" placeholder for unconfigured data widgets. |
WidgetShell | The header + content frame used while rendering. |
SettingsGroup | Reusable form building blocks for config panels. |
To add a widget, follow Creating a widget.