Install and requirements
- Node.js ^22.18.0 or >=24.11.0 for installation/development/server rendering
- Browser DOM only for the default browser entrypoint
- No DOM globals required by white-label-view/server
import View from 'white-label-view';
import View from 'white-label-view/server';
import {raw} from 'white-label-view/jsx-runtime';
Rendering contract
Browser View templates must resolve to exactly one DOM element, one trusted single-root HTML string, or White Label JSX that becomes one root element. Invalid or multi-root output throws TypeError without replacing the last successful root.
Server View accepts trusted HTML strings or White Label JSX and stores the most recently rendered HTML for toString(). It does not emulate DOM nodes, mounting, delegated events, focus, or animation frames.
const view = new View({
parentElement: document.querySelector('main'),
model,
template: data => <section>{data.name}</section>
}).initialize();
Browser lifecycle
initialize() performs a synchronous render. A successful mount/replacement establishes model binding, calls addListeners(), then afterMount(). Before replacement or destruction, removeListeners() runs and owned children are cleaned up.
Equal attached output can preserve the existing root. Use update(element, data) for deliberate in-place changes; return false to fall back to normal rendering.
class MenuView extends View {
addListeners() {
this.delegated.on('click', 'a', this.handleClick);
return this;
}
}
Model binding and batching
A model is treated as observable only when it exposes on() and removeListener(). If it exposes get(), View passes get() to the template; otherwise it passes the model itself.
batchUpdates: true coalesces model-triggered browser renders into one requestAnimationFrame. Manual render() stays synchronous. Server rendering is always synchronous.
JSX runtime and trust
The optional automatic JSX runtime escapes child text and attribute values by default. It supports fragments, arrays, function components, boolean attributes, className, htmlFor, and style objects.
raw() is an explicit trust escape hatch. Pass only markup the application already trusts or has sanitized. Direct HTML-string templates are also caller-trusted input.
const template = () => <section>{raw('<strong>Trusted</strong>')}</section>;
Browser constructor settings
new View(settings?)
Create a browser View.
| Parameter | Type | Default | Description |
|---|
parentElement | Element | — | Parent that owns the rendered root. |
element | Element | — | Existing root to adopt. |
model | object | — | Data source; observable when it exposes on/removeListener. |
template | (data) => string | Node | JSXMarkup | — | Render function; browser output must resolve to one element. |
update | (element, data) => boolean | — | Optional in-place update hook. |
batchUpdates | boolean | false | Coalesce model-driven renders into an animation frame. |
- Returns
- A View instance.
- Runtime
- Browser
Browser View API
update(element, data)
In-place update hook used before template replacement.
- Returns
- boolean; true means handled, false uses normal template rendering.
- Runtime
- Browser
setModel(model?)
Move model binding and synchronously render current data.
- Returns
- The same View instance.
- Runtime
- Browser
initialize()
Perform the initial synchronous render and lifecycle setup.
- Returns
- The same View instance.
- Runtime
- Browser
requestRender()
Render now or queue one animation-frame render when batching is enabled.
- Returns
- The same View instance.
- Runtime
- Browser
addChild(child)
Give this View cleanup ownership of another View without automatically mounting it.
- Returns
- The parent View.
- Throws / rejects
- TypeError for ownership cycles or a child already owned elsewhere.
- Runtime
- Browser
releaseChild(child)
Relinquish cleanup ownership without destroying the child.
- Returns
- The parent View.
- Runtime
- Browser
destroy()
Release listeners, binding, queued work, owned children, and the DOM root.
- Returns
- The same View instance; it may be initialized again.
- Runtime
- Browser
initializeModelBinding()
Subscribe once to an observable model's change event.
- Returns
- undefined.
- Runtime
- Browser
destroyModelBinding()
Release the owned model subscription and cancel queued rendering.
- Returns
- undefined.
- Runtime
- Browser
addListeners()
Subclass hook called after root installation.
- Returns
- The same View instance by default.
- Runtime
- Browser
removeListeners()
Subclass hook called before root replacement or destruction.
- Returns
- The same View instance by default.
- Runtime
- Browser
afterMount()
Subclass hook called after insertion/adoption and listener setup.
- Returns
- The same View instance by default.
- Runtime
- Browser
delegate(scope?)
Create a caller-owned delegated-event registry scoped to an element or the current root.
- Returns
- DelegatedEvents registry.
- Runtime
- Browser
render()
Synchronously mount, preserve, update, or replace the root.
- Returns
- The same View instance.
- Throws / rejects
- TypeError when template output does not resolve to exactly one browser element.
- Runtime
- Browser
DelegatedEvents API
delegated.on(type, selector, callback, options?)
Register a native delegated event listener. once is consumed only by a matching event.
- Returns
- The same DelegatedEvents registry.
- Runtime
- Browser
delegated.off(type, selector?, callback?, options?)
Remove matching delegated registrations, optionally scoped by selector/callback/capture.
- Returns
- The same DelegatedEvents registry.
- Runtime
- Browser
delegated.clear()
Remove every native and abort listener owned by the registry.
- Returns
- The same DelegatedEvents registry.
- Runtime
- Browser
Server View API
setModel(model?)
Move model binding and synchronously render current data.
- Returns
- The same server View.
- Runtime
- Node.js / DOM-free
initialize()
Render current state and initialize the server lifecycle.
- Returns
- The same server View.
- Runtime
- Node.js / DOM-free
addChild(child)
Register child cleanup ownership.
- Returns
- The parent server View.
- Throws / rejects
- TypeError for ownership cycles or conflicting ownership.
- Runtime
- Node.js / DOM-free
releaseChild(child)
Release ownership without destroying the child.
- Returns
- The parent server View.
- Runtime
- Node.js / DOM-free
initializeModelBinding()
Subscribe to observable model changes.
- Returns
- The same server View.
- Runtime
- Node.js / DOM-free
destroyModelBinding()
Release the model subscription.
- Returns
- The same server View.
- Runtime
- Node.js / DOM-free
render()
Synchronously render the template into stored HTML.
- Returns
- The same server View.
- Throws / rejects
- TypeError for output that is neither a string nor White Label JSX markup.
- Runtime
- Node.js / DOM-free
toString()
Read the most recently rendered HTML.
- Returns
- HTML string, or an empty string before/after output is cleared.
- Runtime
- Node.js / DOM-free
destroy()
Destroy children, release subscriptions, and clear stored output.
- Returns
- The same server View.
- Runtime
- Node.js / DOM-free
JSX runtime API
raw(value)
Mark caller-owned markup as trusted so it is inserted without escaping.
- Returns
- RawMarkup.
- Runtime
- Browser + Node.js
- Never pass untrusted user content directly.
isJSXMarkup(value)
Identify output created by the White Label JSX runtime.
- Returns
- Type-predicate boolean.
- Runtime
- Browser + Node.js
jsx(type, props)
Automatic JSX runtime entry point.
- Returns
- JSXMarkup.
- Runtime
- Browser + Node.js
jsxs(type, props)
Automatic JSX runtime alias used for multi-child output.
- Returns
- JSXMarkup.
- Runtime
- Browser + Node.js
jsxDEV(type, props)
Development JSX runtime alias.
- Returns
- JSXMarkup.
- Runtime
- Browser + Node.js
Fragment
Fragment token understood by the JSX runtime.
- Returns
- symbol.
- Runtime
- Browser + Node.js
TypeScript
View.Settings and View.Model expose the supported browser/server contracts.
Template data is unknown by design; application code should narrow domain data before accessing fields.
Security and trust boundaries
JSX escapes normal dynamic text/attributes; raw() and HTML-string templates are trusted caller input.
View does not provide a sanitizer. Sanitize untrusted HTML before crossing a trusted-markup boundary.
Design boundaries
View owns rendering mechanics and rendering lifecycle, not application state, routing, networking, CSS, sanitization policy, or application-wide events.
The browser entrypoint does not provide automatic hydration or claim to reconcile arbitrary server DOM with browser state.