@dynamic-widget/angular
v1.2.0
Published
Angular wrapper for Dynamic Widget.
Maintainers
Readme
@dynamic-widget/angular
Angular standalone component and injectable feature service for schema-driven forms and dashboards, built on @dynamic-widget/core. Editable tabs, validation, enterprise charts, rules engine, designer events, and visual schema designer (dw-schema-designer).
Current release: 1.2.0 — Depends on @dynamic-widget/core ^1.2.0. See monorepo CHANGELOG.
Live demo & docs: https://dynamic-widget-app.vercel.app/ — try the interactive demo, /designer, or read the Angular API guide.
What's new in 1.2.0
SchemaDesignerComponent(dw-schema-designer) — templates, undo/redo, import modal (merge/replace + diff), field-type modal, validation jump-to-field.enterpriseLicenseKey,locale,dataProvideron schema designer for live preview.- Controlled
[schema]+(schemaChange)preserves undo history (echo updates are not reapplied as external resets).
Ships as ESM TypeScript declarations. Works with Angular 18+ and 19 (
@angular/core,@angular/common,@angular/forms). Import@dynamic-widget/themesCSS inangular.jsonor global styles.
Keywords: dynamic-widget angular standalone schema-driven forms dashboard i18n data-binding editable-tabs
Install
npm install @dynamic-widget/angular @dynamic-widget/themes
# Adds @dynamic-widget/core automatically.
# Peer deps: @angular/core ^18 || ^19, @angular/common ^18 || ^19, @angular/forms ^18 || ^19.
# Optional enterprise:
npm install @dynamic-widget/enterpriseUsage — component
// app.component.ts
import { Component } from "@angular/core";
import { DynamicWidgetComponent } from "@dynamic-widget/angular";
import type { WidgetSchema } from "@dynamic-widget/core";
@Component({
selector: "app-root",
standalone: true,
imports: [DynamicWidgetComponent],
template: `
<dynamic-widget
[schema]="schema"
[values]="values"
(valuesChange)="values = $event"
(widgetEvent)="onWidgetEvent($event)"
enterpriseLicenseKey=""
/>
`,
})
export class AppComponent {
values: Record<string, unknown> = {};
schema: WidgetSchema = {
widgets: [{ id: "email", type: "input", field: "email", label: "Email" }],
};
onWidgetEvent(event: unknown) {
console.log(event);
}
}Add styles once in angular.json:
"styles": ["node_modules/@dynamic-widget/themes/dynamic-widget.css"]Usage — i18n (language dropdown)
Bind a host <select> to locale; use labelKey and schema.locales on the schema:
<select [(ngModel)]="locale" aria-label="Language">
<option value="en">English</option>
<option value="fr">Français</option>
<option value="ar">العربية</option>
</select>
<dynamic-widget [schema]="schema" [locale]="locale" [values]="values" (valuesChange)="values = $event" />Guide: Internationalization · Demo: Locale / i18n scenario.
Usage — async binding
import { createFetchDataProvider } from "@dynamic-widget/core";
readonly dataProvider = createFetchDataProvider();<dynamic-widget [schema]="schema" [dataProvider]="dataProvider" [values]="values" (valuesChange)="values = $event" />Declare optionsFrom on select nodes; dependent lists use dependsOn and {field} URL tokens. Demo: Async binding on /demo.
Community widgets markdown and fileUpload need no extra inputs. Virtual tables use props.virtualize with an enterprise licence.
Usage — visual schema designer (dw-schema-designer)
Import themes (includes schema designer CSS when you use the main stylesheet):
@import "@dynamic-widget/themes/dynamic-widget.css";import { Component, signal } from "@angular/core";
import { SchemaDesignerComponent } from "@dynamic-widget/angular";
import { createEmptySchema, createFetchDataProvider, type WidgetSchema, type WidgetValues } from "@dynamic-widget/core";
@Component({
standalone: true,
imports: [SchemaDesignerComponent],
template: `
<dw-schema-designer
[schema]="schema()"
(schemaChange)="schema.set($event)"
[values]="values()"
(valuesChange)="values.set($event)"
[enterpriseLicenseKey]="licenseKey"
[locale]="locale"
[dataProvider]="dataProvider"
previewTitle="Form preview"
/>
`
})
export class FormBuilderPage {
readonly schema = signal<WidgetSchema>(createEmptySchema("My form"));
readonly values = signal<WidgetValues>({});
readonly licenseKey = "";
readonly locale = "en";
readonly dataProvider = createFetchDataProvider();
}| Input | Description |
| --- | --- |
| schema | Form schema (emit updates with schemaChange). |
| values | Preview values (valuesChange). |
| palette | Optional custom SchemaDesignerPaletteGroup[] (default: form fields + dashboard: metric, table, chart). |
| readonly | Disable add/edit/remove/reorder. |
| showJsonPanel | Show collapsible schema JSON (default true). |
| embedded | Compact chrome for embeds (hides default title row). |
| dark | Applies dark theme to designer shell and live preview. |
| previewTitle | Preview panel heading (default "Form preview"). |
| locale | Passed to inner <dynamic-widget> preview. |
| dataProvider | Async optionsFrom in preview. |
| enterpriseLicenseKey | Enables chart/plugin preview when licence modules allow. |
Toolbar includes templates, undo/redo, and import JSON (merge or replace with summary). Guide: Schema designer.
Live demo: /designer. For multi-tab dashboards with seven chart types and live chart editing in tab chrome, use editable tabs in the demo workbench (separate from the form schema designer; uses canDesigner).
Usage — service
Enterprise charting and AI helpers without mounting the full widget:
import { inject } from "@angular/core";
import { DynamicWidgetFeatureService } from "@dynamic-widget/angular";
import { syncEnterpriseLicenseFromKey } from "@dynamic-widget/angular";
// In a component or APP_INITIALIZER:
syncEnterpriseLicenseFromKey("YOUR-LICENSE-KEY");
const features = inject(DynamicWidgetFeatureService);
const insight = features.ai({ widgetType: "chart", context: "demo" });
const spec = features.charting.createChartSpec({ type: "bar", data: [] });Re-exports all public symbols from @dynamic-widget/core (including createSchemaDesignerController for headless UIs).
Angular vs React naming
| Angular | React |
| --- | --- |
| SchemaDesignerComponent selector dw-schema-designer | SchemaDesigner |
| (schemaChange) | onSchemaChange |
API
DynamicWidgetComponent inputs
| Input | Type | Description |
| --- | --- | --- |
| schema | WidgetSchema | Required. Root widget tree. |
| locale | string | Active locale tag; resolves labelKey from schema.locales. |
| dataProvider | DataProvider | Fetches JSON for optionsFrom (internal bindingCache per component). |
| values | WidgetValues | Bound field values. |
| dark | boolean | Dark theme. |
| enterpriseLicenseKey | string | Activates @dynamic-widget/enterprise when valid. |
| rules | WidgetRule[] | Rules engine definitions. |
| aiInsightProvider | AiInsightProvider | Custom AI insight provider. |
| tabsContentOnly | boolean | Preview mode: widgets only, no insert bar. |
DynamicWidgetComponent outputs
| Output | Type | Description |
| --- | --- | --- |
| valuesChange | WidgetValues | Emitted when form values change. |
| widgetEvent | WidgetEventPayload | Tab designer and widget actions. |
| enterpriseStatusChange | EnterpriseWidgetStatus | License and feature flags snapshot. |
DynamicWidgetFeatureService
| Member | Description |
| --- | --- |
| ai | createAiWidgetInsight from core |
| charting | { createChartSpec, renderChartToSvg } |
License helpers
syncEnterpriseLicenseFromKey(key), isEnterpriseUnlocked() — thin wrappers over @dynamic-widget/enterprise.
Browser support
Requires a modern browser (see @dynamic-widget/core). The component renders client-side DOM via the shared renderer; use tabsContentOnly for read-only preview surfaces.
Angular SSR: only mount <dynamic-widget> in the browser (e.g. afterNextRender or *ngIf="isBrowser") because rendering uses document and HTMLElement.
Related packages
@dynamic-widget/core— framework-agnostic engine (auto-installed as a dependency).@dynamic-widget/themes— shared CSS.@dynamic-widget/enterprise— optional licensing and gated APIs.@dynamic-widget/react— React component on the same core.@dynamic-widget/js— vanillacreateDynamicWidgethost.
