ElementNode
Core node representing a single HTML element in the Domphy tree.
import { ElementNode } from "@domphy/core"
const node = new ElementNode({ div: "Hello World" })
node.render(document.body)Constructor
new ElementNode(domphyElement: DomphyElement, parent?: ElementNode | null)Properties
| Property | Type | Description |
|---|---|---|
type | string | Always "ElementNode" |
parent | ElementNode | null | Parent node. null if root |
tagName | TagName | HTML tag name e.g. "div" |
children | ElementList | Child nodes |
styles | StyleList | Scoped CSS styles |
attributes | AttributeList | HTML attributes |
domElement | HTMLElement | null | Mounted DOM element |
key | string | number | null | Identity key for diffing |
nodeId | string | Hash used for scoped CSS class generation |
_portal | ((root) => Element) | undefined | Redirects DOM mount target when present |
The scoped CSS class is attached through node.attributes using the pattern ${tagName}_${nodeId}.
Methods
render(domElement)
Creates a DOM node and appends it to the target.
node.render(document.body)
node.render(document.getElementById("app")!)mount(domElement, domStyle?)
Hydrates onto an existing DOM element. Used for SSR.
const html = node.generateHTML()
const css = node.generateCSS()
// ... send to client ...
const domStyle = document.getElementById("domphy-style") as HTMLStyleElement
node.mount(document.getElementById("app")!, domStyle)When doing SSR, render CSS into <style id="domphy-style">...</style> on the server, then pass that same style element to mount() on the client.
remove()
Removes this node from its parent.
node.remove()patch(rawElement)
Replaces the node's element descriptor in-place. Triggers a reconciliation pass to apply the new props/children/style to the DOM without unmounting.
node.patch({ div: "updated content", class: "active" })| Parameter | Type | Description |
|---|---|---|
rawElement | DomphyElement | New element descriptor to apply |
Unlike merge() which deep-merges, patch() replaces the full descriptor. Used internally by list reconciliation (a reactive list/content function reusing a node by key or position) and explicit update flows.
patch() reconciles the node's own flat style properties (e.g. color, padding) — properties present before but absent from the new descriptor are removed, matching how attributes are reconciled. Nested selector blocks are not reconciled (&:hover, @media, @keyframes, @font-face): they are set once at construction and assumed stable across reuse. A value that must change after construction under a nested selector needs its own reactive function (color: (l) => …) rather than a plain value recomputed by the caller.
merge(partial)
Updates this node from a partial element descriptor.
node.merge({ style: { color: "red" }, class: "active" })addEvent(name, callback)
Registers a DOM event listener. Multiple callbacks are chained.
node.addEvent("click", (e, node) => console.log(node.tagName))addHook(name, callback)
Registers a lifecycle hook. Multiple callbacks are chained.
node.addHook("Mount", (node) => console.log("mounted"))
node.addHook("BeforeRemove", (node, done) => {
animate(node.domElement).then(done)
})| Hook | Trigger |
|---|---|
Schedule | (node, rawElement) => void — fired before parsing; use to apply context-aware patches via merge(rawElement, ...) |
Init | (node) => void — fired after parsing, before insertion into the tree |
Insert | Node added to children list |
Mount | DOM element created |
BeforeUpdate | Before children diff |
Update | After children diff |
BeforeRemove | Before DOM removal — call done() to proceed |
Remove | After DOM removal |
Error | Caught error from a reactive child ((node, error, reset) => void) — call reset() to clear children and render fallback |
getRoot()
Returns the root node of the tree.
const root = node.getRoot()getContext(name) / setContext(name, value)
Inherited context — walks up the tree to find the nearest value.
// Parent
node.setContext("theme", "dark")
// Any descendant
const theme = node.getContext("theme") // "dark"getMetadata(name) / setMetadata(key, value)
Local metadata — not inherited by children.
node.setMetadata("id", "user-123")
node.getMetadata("id") // "user-123"getBehavior(key)
Looks up a per-node behavior instance attached via behavior(), walking up through ancestors (same pattern as getContext/getMetadata) — a behavior is declared on the element that owns the concern, but the event that needs it often fires on a descendant.
import { behavior } from "@domphy/core"
const anchorPartial = behavior("floating", attachFloating, { open: openState })
// later, from a live-rebound trigger event handler:
onClick: (e, node) => node.getBehavior("floating")?.show()Returns undefined if the key was never declared on this node or an ancestor, or was declared but hasn't attached yet (construction-time, before Mount).
generateHTML()
Generates HTML string. Used for SSR.
const html = node.generateHTML()
// "<div class="div_abc123">Hello</div>"generateCSS()
Generates CSS string for this node and all descendants. Used for SSR.
const css = node.generateCSS()