Introduction
@ngaf/render is the Angular rendering engine for json-render specs. It takes a declarative JSON specification and renders it into a live Angular component tree -- with reactive state, event handling, and conditional rendering built in.
#Why @ngaf/render?
Building dynamic UIs from server-driven specifications is a common pattern in AI applications, form builders, and CMS-powered frontends. @ngaf/render bridges the gap between @json-render/core (a framework-agnostic spec evaluation engine) and Angular's component model.
Instead of writing imperative rendering logic, you describe your UI as a JSON spec and let the library handle the rest:
The library resolves Text from your component registry, evaluates the $state expression against the state store, and renders your TextComponent with label set to "Hello, world!". When the state changes, the component updates automatically via Angular Signals.
#How It Relates to @json-render/core
@json-render/core provides the spec format and the evaluation engine -- it resolves prop expressions ($state, $item, $index, $bindState, $fn), evaluates visibility conditions, and resolves bindings. It is framework-agnostic and has no Angular dependency.
@ngaf/render is the Angular adapter layer. It provides:
- Component registry -- maps spec element types (like
"Text"or"Card") to Angular component classes - Signal-based state store -- an Angular Signals-backed implementation of the
StateStoreinterface from@json-render/core - Recursive rendering -- a component tree that walks the spec and dynamically renders Angular components via
NgComponentOutlet - Dependency injection integration --
provideRender()for global config,RENDER_CONTEXTfor child components, andREPEAT_SCOPEfor repeat iterations
#Key Concepts
#Specs
A spec is a JSON object that describes a UI tree. It has three parts:
root-- the key of the root elementelements-- a flat map of element keys toUIElementdefinitionsstate-- (optional) initial state for the state store
#Registry
A registry maps element type names to Angular component classes. You define one with defineAngularRegistry():
#State Store
The state store holds the reactive state that drives your UI. Values are accessed via JSON Pointer paths (like /user/name). The library provides signalStateStore(), which uses Angular Signals internally so that state changes trigger change detection automatically.
#Component Input Contract
Every component rendered by the library receives a standard set of inputs defined by the AngularComponentInputs interface:
emit-- a function to dispatch eventsbindings-- a map of two-way binding pathsloading-- whether the spec is currently streamingchildKeys-- keys for recursive child renderingspec-- the full spec (for child resolution)- Plus any resolved props from the element definition
#Events and Handlers
Elements can define event handlers via the on property. When a component calls emit('submit'), the library looks up the corresponding action and dispatches it to a registered handler function.
#Architecture Overview
The rendering pipeline works as follows:
RenderSpecComponentreceives a spec, registry, and store. It resolves defaults fromRENDER_CONFIG(provided byprovideRender()) and provides aRENDER_CONTEXTto its children.RenderElementComponentreceives an element key and the spec. For each element, it:- Looks up the
UIElementdefinition fromspec.elements - Resolves the Angular component class from the registry
- Evaluates the
visiblecondition - Resolves prop expressions and bindings using
@json-render/core - Renders the component via
NgComponentOutletwith the resolved inputs
- Looks up the
- For elements with
repeat, the library iterates over the state array and creates a childInjectorwith aRepeatScopefor each item.
#Next Steps
Install the package and configure your Angular application
Render your first spec in 5 minutes
Learn how to create and configure component registries
Full RenderSpecComponent API reference
Subscribe to per-context lifecycle signals via RENDER_LIFECYCLE