iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
For forms whose fields are genuinely determined at runtime, Angular’s Signal Forms can use one typed JSON-style configuration to build the model, validation schema and rendered controls. This keeps those parts aligned as the configuration changes. If the form’s structure is known when you build the application, a static form is usually a better fit because it offers stronger compile-time checking and simpler testing.
When should you use a JSON-driven form?
Use runtime configuration when the application cannot know its form structure at build time—for example, when a backend, admin panel, tenant setting or CMS determines which fields appear. The approach can also suit rules that vary with user roles, feature flags or business requirements, and forms that need to evolve without a frontend redeploy. Angular’s dynamic forms with JSON guide describes this use case and demonstrates it with Signal Forms.
If the fields are fixed in the application, prefer a static form. Its structure is easier for TypeScript to check and for developers to test and use with tooling. Runtime configuration trades some of that directness for flexibility.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →How does the configuration drive a Signal Form?
Angular describes the pattern this way: “This guide shows how to build forms whose model, schema, validation, and rendering are all derived from a single runtime configuration.” The key is to derive the model and schema from the same field definitions, then render those definitions rather than maintaining separate lists of controls and rules.
#1 Best Overall
Define fields as a discriminated union
Represent each field with a kind discriminator, such as a text or number field. Each branch can include a name, label and the validation settings appropriate to that kind. The discriminator lets the implementation select both a compatible initial value and the corresponding input and validators.
Build the model and schema from the same definitions
A model-building helper walks the configuration and creates a property for every field. The example initializes text values as empty strings and numeric values as null. Starting a number at 0 can be misleading: a required numeric field would already have a value, and a positive minimum could fail before the user enters anything.
Rank #2
A schema-building helper walks the same definitions and adds the matching rules. The example includes required text fields and numeric minimum and maximum constraints. Deriving both pieces from one configuration reduces the chance that a field’s initial value, rendered control and validation rules drift apart.
Recommended Free Tools
The example assumes configuration is available synchronously when the component constructs the form. It illustrates the derivation pattern; it is not a complete lifecycle for fetching configuration asynchronously. An application that loads configuration later must account for that lifecycle and validate incoming configuration and field names before using them.
Rank #3
How do you render fields from the configuration?
Use Angular’s @for to iterate over the field definitions, then switch on each field’s kind to choose the appropriate input. Bind each input to the matching field path in the Signal Form.
There is a TypeScript template-checking boundary here: narrowing config.kind in a branch does not automatically narrow a separate dynamic lookup such as dynamicForm[name]. The Angular example uses typed accessors and casts at the binding point; the selected kind branch is what makes the runtime type appropriate. Treat this as a consequence of dynamic indexing, not as a substitute for validating configuration or field names.
Rank #4
How do conditional rules and visibility work?
A field configuration can include a when discriminator that names another field and the value that activates a rule. An applyWhen() rule applies the configured validation when that condition is true. When the condition becomes false, the rule deactivates and the field’s validation state clears. For conditional visibility, Angular’s guide uses hidden() on the field path.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Signal Forms schemas set up the logic tree when a form is created, while rule functions express reactive behavior as values change. This lets a schema describe dependencies and conditions without treating the configuration as a one-time rendering decision. See Angular’s schemas and schema composability guide for the broader model.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.How should you handle repeated fields?
For a repeated group represented as an array, provide array defaults in the model and use applyEach() to apply validation to each item. Add or remove items in the model as needed; a newly added item receives fresh validation state, and removing an item removes its associated state.
Use this when repeated items belong to the Signal Forms model and schema. It is not the same API as a reactive-forms FormArray, which manages a variable number of explicit controls.
How does this differ from reactive forms and FormArray?
Angular supports distinct forms approaches. The JSON-driven example discussed here uses Signal Forms; reactive forms use explicitly constructed controls and provide synchronous access to form data. A reactive-forms FormArray manages any number of unnamed child controls, with values and validation status calculated from those controls; controls can be inserted or removed at runtime. Reactive forms require the ReactiveFormsModule infrastructure and directives in the relevant NgModule.
| Approach | Where structure and rules live | Repeated children | Best fit |
|---|---|---|---|
| Signal Forms driven by runtime configuration | A configuration drives the model, schema and rendering together. | Array defaults and per-item rules can be derived and updated in the model. | Fields or rules depend on runtime data such as tenant settings or user roles. |
| Static form | Known in application code at build time. | Use a fixed structure when the number of children is known. | Structure is stable and stronger compile-time checking, straightforward testing and tooling are priorities. |
| Reactive forms with FormArray | Controls are constructed explicitly; reactive forms expose data synchronously. | FormArray manages a runtime-variable number of controls. | The control-based reactive-forms model fits the application, including when child controls must be added or removed. |
These are different APIs, not interchangeable names for the same technique. Angular’s forms overview covers the broader approaches, and its reactive forms guide explains the control-based model and FormArray. The ReactiveFormsModule API reference documents the module infrastructure. Angular also has a version-specific Angular v18 dynamic forms tutorial for metadata-driven reactive forms; it is a different guide and should not be confused with the current JSON-driven Signal Forms example.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

