Specs
A spec is the JSON object that describes your entire UI tree. It tells @ngaf/render what to render, how to wire state, and when to show or hide elements.
Spec Format
Every spec has three top-level properties:
| Property | Type | Description |
|---|---|---|
root | string | The key in elements that is the entry point for rendering |
elements | Record<string, UIElement> | A flat map of all element definitions, keyed by unique identifiers |
state | object | (Optional) Initial state used to create an internal state store when no external store is provided |
Elements are stored in a flat map rather than a nested tree. Parent-child relationships are expressed through the children property, which contains keys pointing to other elements in the map. This design enables efficient lookups and makes specs easy to generate from server-side tools.
UIElement Properties
Each element in the elements map is a UIElement object:
| Property | Type | Description |
|---|---|---|
type | string | The name used to look up the component in the registry |
props | Record<string, unknown> | Input values for the component. Can be static or dynamic expressions |
children | string[] | Keys of child elements in the elements map |
visible | unknown | Visibility condition -- evaluated by @json-render/core |
repeat | { statePath: string } | Repeat configuration for rendering lists |
on | Record<string, EventBinding> | Event handler bindings |
Prop Expressions
Props can be static values or dynamic expressions resolved by @json-render/core:
$state -- Read from State
Reads a value from the state store at the given JSON Pointer path:
$bindState -- Two-Way Binding
Like $state, but also populates the bindings input so the component can write back to the store:
$item -- Repeat Item Value
Inside a repeat loop, $item resolves to the current array item. Pass an empty string to get the whole item, or a path to access a nested property:
$index -- Repeat Index
Inside a repeat loop, $index resolves to the current zero-based iteration index:
$fn -- Computed Function
Calls a registered computed function with the given arguments:
Children
The children property is an array of element keys that reference other entries in the elements map:
The rendered ContainerComponent receives childKeys: ['heading', 'body'] and the full spec, enabling it to recursively render its children using RenderElementComponent.
Deeply Nested Trees
Because children reference keys in the same flat map, you can build arbitrarily deep trees:
Conditional Rendering
The visible property controls whether an element is rendered. When the condition evaluates to a falsy value, the element and all its children are excluded from the DOM.
Static Visibility
State-Driven Visibility
When /showMessage is true in the state store, the element renders. When it is false, it is removed.
Default Visibility
When visible is omitted or undefined, the element is visible by default.
Repeat Loops
The repeat property renders an element once for each item in a state array:
For each item in the array at /todos, the library:
- Creates a
RepeatScopewith theitem,index, andbasePath(e.g.,/todos/0) - Provides the scope via a child
Injectorusing theREPEAT_SCOPEtoken - Resolves props using the repeat scope context --
$itemand$indexexpressions are evaluated per-iteration - Renders the component with the resolved inputs
When an element has repeat, visibility evaluation is handled differently -- all items are rendered. To conditionally render individual repeat items, use conditional logic within the rendered component itself.
Complete Example
Here is a spec that combines children, state expressions, conditional rendering, and repeat loops: