On This Page
Native Renderer
The native engine is the default. Its factory produces components that extend HTMLElement directly, Renderer walks the AST into DOM, and ServerRenderer produces the HTML string that renderToString returns.
Fine Grained Reactivity
Dynamic positions get their own Reaction. When a signal changes, only the reactions that read it wake, and each writes to the one DOM position it owns.
<h1>{title}</h1><span class="count">{count}</span>Changing count wakes one reaction and assigns one text node. title is untouched and its reaction never runs.
The AST is walked once, when the instance first renders. After that, updates flow only through the reactions bound during that walk. Nothing re-renders at the component level.
Rendering
Renderer.render() returns a DocumentFragment in three phases.
| Phase | Produces |
|---|---|
| Assemble | One HTML string with a marker at every dynamic position, plus an entries array describing each marker |
| Parse | A single innerHTML assignment on a <template>, so the browser resolves nesting |
| Bind | Two TreeWalker passes that find the markers and create a reaction per binding |
Assembly is a pure function, which is what lets the client and the server share it. Parsed templates are cached by their HTML string and cloned per instance, so repeated instances of a component parse once.
Markers
| Position | Marker |
|---|---|
| Text content | <!--sui:v1:0--> |
| Attribute value | __sui0__ |
| Block directive | <!--sui-block:v1:0--> |
Each marker carries an index into entries. Whether a marker is an attribute or text, boolean or quoted, property or event is decided during assembly by analyzePosition, not at bind time.
Block Directives
{#if}, {#each}, {#async} and {#rerender} own a region of DOM rather than a single position. Each keeps a persistent anchor node, the nodes it inserted, and the reaction scopes belonging to them.
When a branch swaps or a row leaves a keyed list, the region disposes its child scopes before removing nodes. Disposal is hierarchical, so a nested block tears down with its parent: reactions stop, timers clear, and delegated listeners unbind without the template tracking them individually.
The anchor stays put, so replacement content lands in the same position.
Server Rendering
ServerRenderer walks the same AST and emits a string instead of nodes. Both renderers share assembly, so they agree on the markup and on where the dynamic positions are. That shared origin is what lets the client wire the server’s tree instead of replacing it.
See Server Rendering for how that handoff works.