Conflict-free Replicated Data Type (CRDT) framework for real-time collaborative applications
XML-aware collaborative types for structured document editing with DOM integration. These types enable collaborative editing of XML/HTML documents while maintaining proper document structure and supporting real-time synchronization.
Container type for XML elements and text nodes, providing the foundation for structured document editing.
/**
* XML container that can hold XML elements and text nodes
*/
class YXmlFragment {
constructor();
/** Number of child elements in the fragment */
readonly length: number;
/** First child element or null if empty */
readonly firstChild: YXmlElement | YXmlText | null;
}Fragment Modification Methods:
/**
* Insert child nodes at the specified index
* @param index - Position to insert at
* @param content - Array of XML elements or text nodes to insert
*/
insert(index: number, content: Array<YXmlElement | YXmlText>): void;
/**
* Insert child nodes after a reference node
* @param ref - Reference node to insert after (null for beginning)
* @param content - Array of XML elements or text nodes to insert
*/
insertAfter(ref: null | Item | YXmlElement | YXmlText, content: Array<YXmlElement | YXmlText>): void;
/**
* Delete child nodes starting at index
* @param index - Starting position for deletion
* @param length - Number of children to delete (default: 1)
*/
delete(index: number, length?: number): void;
/**
* Append child nodes to the end
* @param content - Array of XML elements or text nodes to append
*/
push(content: Array<YXmlElement | YXmlText>): void;
/**
* Prepend child nodes to the beginning
* @param content - Array of XML elements or text nodes to prepend
*/
unshift(content: Array<YXmlElement | YXmlText>): void;Fragment Access Methods:
/**
* Get child node at the specified index
* @param index - Index of child to retrieve
* @returns Child node or undefined
*/
get(index: number): YXmlElement | YXmlText;
/**
* Get slice of children as JavaScript Array
* @param start - Start index (default: 0)
* @param end - End index (default: length)
* @returns Array of child nodes
*/
slice(start?: number, end?: number): Array<YXmlElement | YXmlText>;
/**
* Convert all children to JavaScript Array
* @returns Array of all child nodes
*/
toArray(): Array<YXmlElement | YXmlText | YXmlHook>;Fragment Iteration and Selection:
/**
* Execute function for each child node
* @param f - Function to execute for each child
*/
forEach(f: (item: YXmlElement | YXmlText, index: number, fragment: YXmlFragment) => void): void;
/**
* Create a tree walker for traversing the fragment
* @param filter - Optional filter function for nodes
* @returns Tree walker instance
*/
createTreeWalker(filter?: (node: AbstractType<any>) => boolean): YXmlTreeWalker;
/**
* Find the first element matching a CSS selector
* @param query - CSS selector string
* @returns First matching element or null
*/
querySelector(query: string): YXmlElement | YXmlText | YXmlHook | null;
/**
* Find all elements matching a CSS selector
* @param query - CSS selector string
* @returns Array of matching elements
*/
querySelectorAll(query: string): Array<YXmlElement | YXmlText | YXmlHook | null>;Fragment Serialization:
/**
* Convert fragment to XML string
* @returns XML string representation
*/
toString(): string;
/**
* Convert to JSON representation
* @returns JSON string
*/
toJSON(): string;
/**
* Convert to DOM DocumentFragment
* @param document - Document to create nodes in (default: globalThis.document)
* @param hooks - Custom hooks for special elements
* @param binding - Optional binding object
* @returns DOM DocumentFragment
*/
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): DocumentFragment;
/**
* Create a copy of the fragment
* @returns New YXmlFragment with same content
*/
clone(): YXmlFragment;Usage Examples:
import * as Y from "yjs";
const doc = new Y.Doc();
const xmlFragment = doc.getXmlFragment("document");
// Create XML elements
const header = new Y.XmlElement("h1");
const paragraph = new Y.XmlElement("p");
const textNode = new Y.XmlText();
textNode.insert(0, "Hello World!");
header.insert(0, [textNode]);
// Insert into fragment
xmlFragment.push([header, paragraph]);
// Query elements
const h1 = xmlFragment.querySelector("h1");
const allPs = xmlFragment.querySelectorAll("p");
// Convert to DOM
const domFragment = xmlFragment.toDOM();
document.body.appendChild(domFragment);XML element with attributes that can contain child elements and text nodes.
/**
* XML element with attributes and children
*/
class YXmlElement<KV = { [key: string]: any }> extends YXmlFragment {
constructor(nodeName?: string);
/** Tag name of the XML element */
readonly nodeName: string;
/** Next sibling element or null */
readonly nextSibling: YXmlElement | YXmlText | null;
/** Previous sibling element or null */
readonly prevSibling: YXmlElement | YXmlText | null;
}Element Attribute Methods:
/**
* Set an attribute on the element
* @param attributeName - Name of the attribute
* @param attributeValue - Value to set
*/
setAttribute<KEY extends keyof KV>(attributeName: KEY, attributeValue: KV[KEY]): void;
/**
* Get an attribute from the element
* @param attributeName - Name of the attribute
* @returns Attribute value or undefined
*/
getAttribute<KEY extends keyof KV>(attributeName: KEY): KV[KEY] | undefined;
/**
* Check if element has an attribute
* @param attributeName - Name of the attribute to check
* @returns True if attribute exists
*/
hasAttribute(attributeName: string): boolean;
/**
* Remove an attribute from the element
* @param attributeName - Name of the attribute to remove
*/
removeAttribute(attributeName: string): void;
/**
* Get all attributes from the element
* @param snapshot - Optional snapshot for historical state
* @returns Object with all attributes
*/
getAttributes(snapshot?: Snapshot): { [key: string]: any };Element Serialization:
/**
* Convert element to XML string with attributes
* @returns XML string representation
*/
toString(): string;
/**
* Convert to DOM Element
* @param document - Document to create element in (default: globalThis.document)
* @param hooks - Custom hooks for special elements
* @param binding - Optional binding object
* @returns DOM Element
*/
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): Element;
/**
* Create a copy of the element
* @returns New YXmlElement with same content and attributes
*/
clone(): YXmlElement<KV>;Usage Examples:
import * as Y from "yjs";
const doc = new Y.Doc();
const xmlFragment = doc.getXmlFragment("document");
// Create an element with attributes
const div = new Y.XmlElement("div");
div.setAttribute("class", "container");
div.setAttribute("id", "main-content");
// Add text content
const text = new Y.XmlText();
text.insert(0, "Hello World!");
div.insert(0, [text]);
// Create nested structure
const article = new Y.XmlElement("article");
const title = new Y.XmlElement("h2");
const titleText = new Y.XmlText();
titleText.insert(0, "Article Title");
title.insert(0, [titleText]);
article.push([title, div]);
xmlFragment.push([article]);
// Work with attributes
console.log(div.getAttribute("class")); // "container"
div.removeAttribute("id");
// Convert to DOM
const domElement = article.toDOM();XML text node with formatting support for rich text within XML structures.
/**
* XML text node with rich formatting capabilities
*/
class YXmlText extends YText {
constructor();
/** Next sibling element or null */
readonly nextSibling: YXmlElement | YXmlText | null;
/** Previous sibling element or null */
readonly prevSibling: YXmlElement | YXmlText | null;
}XML Text Methods:
/**
* Convert to formatted XML string
* @returns XML string with formatting
*/
toString(): string;
/**
* Convert to JSON representation
* @returns JSON string
*/
toJSON(): string;
/**
* Convert to DOM Text node
* @param document - Document to create text node in (default: globalThis.document)
* @param hooks - Custom hooks for special formatting
* @param binding - Optional binding object
* @returns DOM Text node
*/
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): Text;
/**
* Create a copy of the text node
* @returns New YXmlText with same content
*/
clone(): YXmlText;Usage Examples:
import * as Y from "yjs";
const doc = new Y.Doc();
const xmlFragment = doc.getXmlFragment("document");
// Create formatted text
const xmlText = new Y.XmlText();
xmlText.insert(0, "Hello ");
xmlText.insert(6, "World", { bold: true });
xmlText.insert(11, "!");
// Add to element
const paragraph = new Y.XmlElement("p");
paragraph.insert(0, [xmlText]);
xmlFragment.push([paragraph]);
// Convert to DOM
const domText = xmlText.toDOM();Custom XML element hook for extending XML functionality with custom components.
/**
* Custom XML hook for extending functionality
*/
class YXmlHook extends YMap {
constructor(hookName: string);
/** Name of the hook */
readonly hookName: string;
}Hook Methods:
/**
* Convert hook to DOM element using custom rendering
* @param document - Document to create element in (default: globalThis.document)
* @param hooks - Hook implementation functions
* @param binding - Optional binding object
* @returns DOM Element
*/
toDOM(document?: Document, hooks?: { [key: string]: any }, binding?: any): Element;
/**
* Create a copy of the hook
* @returns New YXmlHook with same hook name and data
*/
clone(): YXmlHook;Usage Examples:
import * as Y from "yjs";
const doc = new Y.Doc();
const xmlFragment = doc.getXmlFragment("document");
// Create a custom hook
const customComponent = new Y.XmlHook("custom-widget");
customComponent.set("type", "chart");
customComponent.set("data", [1, 2, 3, 4, 5]);
xmlFragment.push([customComponent]);
// Convert to DOM with custom hook handler
const domFragment = xmlFragment.toDOM(document, {
"custom-widget": (hook) => {
const element = document.createElement("div");
element.className = "custom-widget";
element.textContent = `Chart with ${hook.get("data").length} points`;
return element;
}
});Iterator for traversing XML tree structures with optional filtering.
/**
* Tree walker for traversing XML structures
*/
class YXmlTreeWalker {
constructor(root: YXmlFragment | YXmlElement, filter?: (node: AbstractType<any>) => boolean);
/**
* Get next node in traversal
* @returns Iterator result with next node
*/
next(): IteratorResult<YXmlElement | YXmlText | YXmlHook>;
/**
* Iterator support for for...of loops
*/
[Symbol.iterator](): YXmlTreeWalker;
}Usage Examples:
import * as Y from "yjs";
const doc = new Y.Doc();
const xmlFragment = doc.getXmlFragment("document");
// Create tree structure
const root = new Y.XmlElement("div");
const child1 = new Y.XmlElement("p");
const child2 = new Y.XmlElement("span");
root.push([child1, child2]);
xmlFragment.push([root]);
// Walk the tree
const walker = xmlFragment.createTreeWalker();
for (const node of walker) {
if (node instanceof Y.XmlElement) {
console.log(`Element: ${node.nodeName}`);
} else if (node instanceof Y.XmlText) {
console.log(`Text: ${node.toString()}`);
}
}
// Walk with filter
const elementWalker = xmlFragment.createTreeWalker(
node => node instanceof Y.XmlElement
);
for (const element of elementWalker) {
console.log(`Element: ${element.nodeName}`);
}Install with Tessl CLI
npx tessl i tessl/npm-yjs