Dynamic rendering in Angular sounds like a fairly narrow technical problem: “I don't know which component I need until runtime.” Angular already gives us several good tools for that.
But there is a big difference between dynamically choosing a component and dynamically constructing an entire UI from a runtime specification.
And that difference becomes especially important with Server-Driven UI and Generative UI.
- : when the problem is really just component selection For simple cases Angular already gives us: This works very well when the application already knows its possible components and runtime logic only decides which one to display.
The advantages are obvious: very little infrastructure, normal Angular lifecycle, AOT-compatible components and a relatively declarative template.
But this approach starts becoming uncomfortable when the runtime input is no longer: and instead becomes: Now we are no longer selecting a component.
We are interpreting a UI description. - : more control, more responsibility Angular also allows components to be instantiated programmatically: This is a powerful primitive.
We control where the component is created, which component is used, how inputs are assigned and when the component is destroyed.
For relatively contained dynamic behavior, this can be exactly what we need.
But once a runtime specification controls many components, application code often starts evolving into something like: Then we add input mapping.
Then events.
Then nested components.
Then state.
Then validation.
Soon the difficult part isn't anymore.
It is everything around it.
3.
Component Registry: separating runtime intent from Angular implementation A natural next step is a registry: Now the runtime specification doesn't need to know anything about Angular classes.
It only says: and the application decides: This separation is more important than it initially appears.
The external system describes intent.
The frontend controls implementation.
And the registry also starts becoming a security boundary: only explicitly registered components can be instantiated.
4.
Recursive rendering: when UI becomes a tree Once a specification can describe nested content, recursion becomes the obvious model.
For example: A renderer can conceptually do: This is where dynamic rendering becomes significantly more powerful.
Forms, dashboards, dialogs, layouts and even entire workflows can now be represented as data.
But this is also where I think an important architectural mistake can happen: A recursive renderer should not blindly render whatever tree it receives.
The UI tree should be validated before it is trusted.
AOT doesn't compile the runtime UI tree There is sometimes confusion around this part.
If the structure is dynamic, how can Angular's AOT compiler know what to render?
The answer is: it doesn't need to know the future structure.
AOT compiles the building blocks.
For example: At runtime, a JSON specification only decides how those already compiled components are composed: So the important distinction is: The UI composition is dynamic.
The Angular component implementations are not.
The runtime is not compiling new Angular components.
It is assembling already compiled components.
This also means we don't need to ship Angular's JIT compiler just to support dynamic UI.
What about sending HTML or Angular templates from the backend?
This is another tempting approach.
Why not return something like: from the server?
Because injecting that HTML into the page does not make it an Angular template.
Angular doesn't suddenly compile arbitrary HTML received from an API into AOT components.
And trying to introduce runtime template compilation changes the trust model completely.
There is a major architectural difference between: and: I strongly prefer the first model.
Especially when AI becomes part of the system.
Dynamic UI also creates a trust problem This is the part I find more interesting than the rendering itself.
Imagine that the UI specification comes from a backend, CMS or AI model.
That specification is now external input.
Even if it is “just JSON”, it controls what the application creates and potentially what the user can do.
So I think dynamic UI should be treated similarly to any other untrusted runtime input.
Unknown components The specification should not be able to instantiate arbitrary Angular classes.
This: should only work if belongs to an explicitly controlled catalog.
The registry therefore isn't only a convenience.
It is an allowlist.
No registry entry?
Nothing gets instantiated.
Props are also external input Even a trusted component can expose dangerous inputs.
Imagine a component receiving: The fact that the component itself is trusted does not automatically mean every possible value supplied to it should be trusted.
So a component catalog should ideally define not only: but also the valid shape of its props.
For example: Now the runtime contract becomes much stronger.
Actions are probably the most important boundary Rendering UI is one thing.
Allowing generated UI to execute application behavior is another.
I would never want a specification like: and definitely not anything remotely resembling: Instead, the specification should only describe an action: and the application resolves it through another controlled registry: The external specification can request a capability.
It cannot invent one.
This gives us a very useful separation: The Component Registry controls what UI can exist.
The Action Registry controls what that UI is allowed to do.
Validate the UI tree before recursively rendering it This is one part I think deserves much more attention.
Suppose a backend or model produces: Thousands of levels deep.
Or maybe the tree contains hundreds of thousands of nodes.
There may be no XSS.
No JavaScript injection.
The JSON may even be structurally valid.
But rendering it can still freeze the browser.
And if the specification uses references: a malformed graph may create recursive cycles.
So validation shouldn't stop at: or even basic schema validation.
A robust runtime boundary may eventually need to reason about component types, props, missing references, illegal parent/child combinations, cycles, maximum depth, maximum node count and potentially maximum repeat expansion.
The architecture I prefer is: Only the last step should create Angular views.
Streaming makes this even more interesting Generative UI adds another complication.
The model may not send the entire UI at once.
Instead: gradually builds the screen.
That means a half-generated UI can naturally contain temporary inconsistencies: a parent may reference a child that simply hasn't arrived yet.
So validating every intermediate state with exactly the same rules as a completed UI can produce false errors.
I think the model should instead be: Potentially with additional lightweight limits while streaming to prevent a generation from growing without bounds.
This becomes much more than “dynamic component rendering”.
It is a small UI runtime.
This is the problem that led me to ngx-json-render While exploring these patterns, I realized that Angular itself already solves the lowest-level problem very well.
Angular knows how to create components.
What I wanted was the layer above that.
That became ngx-json-render.
The library takes a different approach from runtime Angular template generation.
An external system produces a JSON UI specification.
The Angular application provides a catalog of components and actions.
The renderer connects the two.
Conceptually: There is no need to send executable Angular templates, use as a component mechanism or evaluate generated JavaScript.
The external system generates UI intent, not frontend code.
The current library already provides the main building blocks around this model: a controlled component registry, catalog-defined component props, registered actions, recursive composition, state/bindings, streaming JSON patches and optional structural validation that