Skip to content
D
Documentation

Vnode

reference
3 min readUpdated

Import these from @grafloria/renderer.

Functions

camelToKebab

camelCase → kebab-case (strokeWidth → stroke-width).

ts
function camelToKebab(str: string): string

createDomElement

Build a fresh detached DOM tree for vnode using the default patcher.

ts
function createDomElement(vnode: VNode, namespace: string = SVG_NS): Element

createForeignObject

Create a foreignObject VNode

Creates a VNode representing an SVG foreignObject element, which allows embedding HTML content inside SVG. Automatically generates a container ID if not provided, and includes a default XHTML div wrapper.

ts
function createForeignObject(options: ForeignObjectOptions): VNode

Parameters

  • options: Configuration options for the foreignObject

Returns A VNode of type 'foreignObject'

Example

typescript
const vnode = createForeignObject({
  nodeId: 'node-1',
  x: 10,
  y: 20,
  width: 200,
  height: 150
});
// Returns: { type: 'foreignObject', props: { x: 10, y: 20, ... }, children: [...] }

Example

With custom container ID and children

typescript
const vnode = createForeignObject({
  nodeId: 'node-1',
  x: 10,
  y: 20,
  width: 200,
  height: 150,
  containerId: 'my-custom-id',
  children: [
    { type: 'div', props: { className: 'custom-content' } }
  ]
});

getContainerId

Get the container ID from a foreignObject VNode

Extracts the container ID from a foreignObject VNode's props. Returns undefined if the VNode is not a foreignObject or doesn't have a container ID.

ts
function getContainerId(vnode: VNode): string | undefined

Parameters

  • vnode: The VNode to extract the container ID from

Returns The container ID if the VNode is a foreignObject, undefined otherwise

Example

typescript
const vnode = createForeignObject({
  nodeId: 'node-1',
  x: 0, y: 0, width: 100, height: 100
});

const containerId = getContainerId(vnode);
// Returns: 'fo-node-1-1'

Example

Non-foreignObject returns undefined

typescript
const rectNode = { type: 'rect', props: { ... } };
const containerId = getContainerId(rectNode);
// Returns: undefined

isForeignObject

Check if a VNode is a foreignObject element

Type guard function that checks if the given VNode represents a foreignObject element.

ts
function isForeignObject(vnode: VNode): boolean

Parameters

  • vnode: The VNode to check

Returns True if the VNode is a foreignObject, false otherwise

Example

typescript
const foNode = createForeignObject({ ... });
const rectNode = { type: 'rect', props: { ... } };

isForeignObject(foNode);   // true
isForeignObject(rectNode); // false

isOpaqueVNode

foreignObject subtrees embed live HTML (framework components, form controls, media). They are OPAQUE to the diff: props are patched, children are left exactly as they are. Diffing into them would wipe whatever was mounted there.

ts
function isOpaqueVNode(vnode: VNode): boolean

reconcile

Reconcile vnode into container using the default patcher.

ts
function reconcile(container: Element, vnode: VNode): Element

serializeStyle

Serialize a style prop. Accepts the object form the renderer emits ({ cursor: 'move' }) as well as a plain string. Returns '' for empty/absent styles.

ts
function serializeStyle(style: unknown): string

Classes

ContainerIdGenerator

Generate unique container IDs for foreignObject elements

ts
class ContainerIdGenerator

Methods

  • static generate(nodeId: string): string (static) — Generate a unique container ID for a foreignObject element
  • static isContainerId(id: string): boolean (static) — Check if a given ID is a valid container ID
  • static getNodeId(containerId: string): string | null (static) — Extract the node ID from a container ID
  • static reset(): void (static) — Reset the internal counter to zero

VNodePatcher

Keyed VNode → DOM reconciler.

ts
const patcher = new VNodePatcher();
patcher.reconcile(container, vnodeTree);   // first call: mount
patcher.reconcile(container, nextTree);    // later calls: diff + patch in place
ts
class VNodePatcher

Methods

  • constructor(options: VNodePatcherOptions = {})
  • get stats(): Readonly<PatchStats> — Work done during the most recent reconcile() call.
  • reconcile(container: Element, vnode: VNode): Element — Diff vnode against whatever this patcher last rendered into container and patch the existing DOM in place. First call (or a lost root) mounts a fresh tree.
  • hydrate(container: Element, vnode: VNode): Element — ADOPT the DOM already inside container as the materialization of vnode, without creating, moving or removing a single node.
  • getMountedElement(container: Element): Element | undefined — The root element currently mounted in container, if any.
  • unmount(container: Element): void — Remove the mounted tree and forget the container.
  • createElement(vnode: VNode, namespace: string = SVG_NS): Element — Build a fresh detached DOM element (deep) for a VNode.
  • patchElement(el: Element, oldVNode: VNode, newVNode: VNode): Element — Diff two VNodes onto an existing element.
  • patchProps( el: Element, oldProps: Record<string, any>, newProps: Record<string, any> ): void — Apply a prop delta to an element (no children touched).

Constants

defaultPatcher

Process-wide default patcher — convenient for the common "one DOM, one tree" case. Instantiate VNodePatcher directly for isolated instances.

ts
const defaultPatcher: VNodePatcher

SVG_NS

SVG namespace — everything outside a foreignObject is created here.

ts
const SVG_NS: "http://www.w3.org/2000/svg"

XHTML_NS

XHTML namespace — foreignObject children are HTML, not SVG.

ts
const XHTML_NS: "http://www.w3.org/1999/xhtml"

Interfaces

ForeignObjectOptions

Options for creating a foreignObject VNode

ts
interface ForeignObjectOptions

Properties

NameTypeDefaultDescription
nodeIdstring
xnumberX coordinate (top-left corner)
ynumberY coordinate (top-left corner)
widthnumberWidth in pixels
heightnumberHeight in pixels
containerId?stringOptional custom container ID If not provided, will be auto-generated using ContainerIdGenerator
children?VNode[]Optional children VNodes If not provided, creates a default XHTML div wrapper
key?stringOptional key for React/Angular diffing optimization

PatchStats

Per-reconcile work counters. Reset at the top of every reconcile() call. Useful as a cheap regression guard: a steady-state frame should create ~0 elements ("no teardown-and-rebuild").

ts
interface PatchStats

Properties

NameTypeDefaultDescription
creatednumberDOM nodes created from scratch.
reusednumberDOM nodes reused in place (patched, not recreated).
movednumberReused DOM nodes that had to move to a new sibling index.
removednumberDOM nodes removed because their VNode disappeared.
skippednumberSubtrees skipped entirely because the VNode object was identical.

VNodePatcherOptions

Options for a patcher instance.

ts
interface VNodePatcherOptions

Properties

NameTypeDefaultDescription
document?Document

Types

VNodeChild

A child slot in a VNode tree. Strings/numbers materialise as text nodes.

ts
type VNodeChild = VNode | string | number | null | undefined;

Members

  • toString(): string — Returns a string representation of a string.
  • valueOf(): string — Returns the primitive value of the specified object.
  • toLocaleString(): string — Returns a date converted to a string using the current locale.

Was this page helpful?