xu-single-view
Pass-through wrapper. Renders its children as a fragment. Used as the outermost wrapper for renderType: 'form', 'detail', and 'component' programs.
Xuda Developer Studio
xu-* attributes. That is the whole rendering language.
Every program owns a progUi: a JSON tree where each node is
{ type: 'element', tagName, attributes, children }. The runtime walks the tree, materializes
the special wrapper elements (xu-single-view, xu-multi-view,
xu-panel, xu-teleport), creates real DOM, and binds the xu-*
attributes. State updates re-evaluate the bindings. There is no virtual DOM and no diff: the directive
surface is the rendering model.
The tree is uniform: there are no special node classes, no component types in the JSON, no slots. A
node is an element with a tag name, attributes, and children. The runtime uses the tag name to decide
whether to materialize a wrapper (anything starting with xu-) or to create a regular DOM
element.
progUi: [
{
type: 'element',
tagName: 'xu-single-view',
attributes: {},
children: [
{
type: 'element',
tagName: 'main',
attributes: { class: 'screen' },
children: [
{ type: 'element', tagName: 'h1', attributes: { 'xu-content': 'Hello' } },
{ type: 'element', tagName: 'p',
attributes: { 'xu-exp:xu-content': '\"Hi, \" + @currentUser.name' } },
{ type: 'element', tagName: 'button',
attributes: { 'xu-click': '{"@count": @count + 1}',
'xu-exp:xu-content': '\"Clicked \" + @count + \" times\"' } }
]
}
]
}
]
The runtime treats four tag names specially. Everything else becomes a regular DOM element with the same name. The wrappers handle composition, iteration, and DOM portals; everything else is plain HTML you happen to be authoring through JSON.
Pass-through wrapper. Renders its children as a fragment. Used as the outermost wrapper for renderType: 'form', 'detail', and 'component' programs.
Loop wrapper. Iterates over the program's progDataSource and renders the children once per row, exposing _KEY (index) and _VAL (item) in the inner scope.
Composition. Mounts another program by id at this position. The embedded program brings its own scope; only globals and the parent's published events are visible from inside.
DOM portal. Moves the children to whatever element matches the to selector. Useful for modals, drawers, toasts, anything that should escape its parent's stacking context.
xu-* attributes the runtime knows about.
These are the directives a node can carry. Each one is a single attribute on a regular element. Static
forms (xu-content, xu-text, xu-html) take literal strings;
expression forms (xu-exp:<target>) take JavaScript expressions evaluated against the
merged scope.
Declares a scoped state object on this node. Children resolve @field against the nearest ancestor that has xu-store, falling back to the program's progFields and then to globals. Stores are mutable: xu-click, xu-bind, and the update workflow action all walk the chain to find the nearest store.
<section xu-store="{'tab':'overview','count':0}">
<p xu-exp:xu-content="'Active tab: ' + @tab"></p>
</section>
Static text or HTML. xu-content and xu-text set the textContent. xu-html sets innerHTML (use carefully). For dynamic values, prefer the xu-exp: form below.
<h1 xu-content="Welcome"></h1> <p xu-html="<em>Trusted markup</em>"></p>
Reactive expression bound to a target attribute. The runtime evaluates the expression against the merged scope and assigns the result. xu-exp:xu-content sets text. xu-exp:xu-class sets the class string. xu-exp:xu-render and xu-exp:xu-show control visibility. Any other target name becomes a regular HTML attribute when the expression has a value, or removes it when the expression returns null.
<p xu-exp:xu-content="'You have ' + @count + ' messages'"></p> <div xu-exp:xu-class="'card ' + (@active ? 'is-active' : '')"></div> <img xu-exp:src="@user.avatarUrl" alt="" /> <a xu-exp:href="'/users/' + @user.id">Open</a>
Bulk-assign HTML attributes from an object. Useful when you want to spread a set of attributes computed elsewhere.
<input xu-attrs="{'type':'email','placeholder':'[email protected]','required':true}" />
Inline iteration. xu-for is an expression that evaluates to an array or object. The element is cloned per entry, with _KEY and _VAL in scope (or whatever names you set with xu-for-key and xu-for-val).
<ul> <li xu-for="@items" xu-for-val="item" xu-exp:xu-content="item.label"></li> </ul>
Conditional visibility. Use the expression form: xu-exp:xu-render="..." or xu-exp:xu-show="...". When the result is falsy the runtime sets the node to hidden and adds display: none.
<div xu-exp:xu-render="@currentUser.id">Signed in.</div> <div xu-exp:xu-render="[email protected]">Please sign in.</div>
Two-way binding for form inputs. The attribute value is the field id in the nearest store. The runtime listens to the input event and writes the value back. Reads also flow back to the input on every re-render unless the input is currently focused.
<input xu-bind="email" /> <p xu-exp:xu-content="'Got: ' + @email"></p>
Click handler that updates state. The attribute value is an object literal where keys are @field targets and values are expressions. All updates are applied at once; the tree re-renders after the batch.
<button xu-click="{'@count': @count + 1, '@last': 'inc'}">Increment</button>
Attach a workflow to any DOM event or any custom event the program publishes. The value is a JSON-encoded array of handlers, each with a workflow step list. Steps include update, navigate, upsert, delete, toast, alert, plugin.
<button xu-on:click='[{"workflow":[
{"data":{"action":"update","name":{"value":"@count: @count + 1"}}},
{"data":{"action":"toast","name":{"value":"\"Bumped\""}}}
]}]'>Bump</button>
The same syntax as xu-click, listening for the corresponding DOM event.
<input xu-focus="{'@hint':true}" xu-blur="{'@hint':false}" />
Inject CSS. xu-style appends the attribute value as a <style> tag in the document head. xu-style-global behaves the same way but is intended for app-wide rules. Both run once on mount.
<div xu-style=".my-card { padding: 1rem; border-radius: 1rem; }"></div>
Lazy-load external scripts. The value is an object whose entries each have a src. The runtime loads each unique src once and re-renders when the script finishes loading. Useful for widgets that need a third-party library.
<div xu-cdn="{'chart':{'src':'https://cdn.jsdelivr.net/npm/chart.js'}}"></div>
Inline script body executed against the node. Receives el (the node) and rerender (a function to trigger another render). Use sparingly; most cases are better served by directives.
<canvas xu-script="el.getContext('2d').fillRect(0,0,40,40);"></canvas>
Run once at mount. Same shape as xu-click: an object of state updates. Useful for seeding default values that depend on globals or route params.
<section xu-store="{}" xu-init="{'@locale': @route.query.lang || @currentLocale}"></section>
@field reference resolves through layered scope.When the runtime evaluates an expression for a node, it builds the scope by walking from the node up to the document root. Each ancestor contributes its store and its loop scope (if any). The closest layer wins on a name conflict. Globals are the outermost layer, so any program field or store field shadows a global of the same name; this is intentional, since shadowing is local.
_KEY, _VAL, or named via xu-for-key / xu-for-val)xu-store)progFields)progDataSource)project.globals.progFields)
The studio renders the program's progUi as an editable tree. Drag a node to reparent it.
Click a node to edit its tag name, its attributes, and its children. The right side shows a live
preview rendered by the same runtime that ships in production. The left side shows the program's
fields, datasource, and events. There is no separate template language to learn; the JSON in the
tree editor is the JSON the runtime renders.