Tree traversal, element querying, and hierarchical navigation utilities with type-safe parent/child relationships, CSS selector support, and comprehensive search capabilities.
Navigate the DOM tree structure with type-safe relationships and optional filtering.
/**
* Get owner document for any node
* @param element - Node to find document for
* @returns Owner document element
*/
function owner(element: SugarElement<Node>): SugarElement<Document>;
/**
* Get document or owner document (handles both cases)
* @param dos - Document or node to get document from
* @returns Document element
*/
function documentOrOwner(dos: SugarElement<Node>): SugarElement<Document>;
/**
* Get document element (html tag) for node
* @param element - Node to find document element for
* @returns Document element (html tag)
*/
function documentElement(element: SugarElement<Node>): SugarElement<HTMLElement>;
/**
* Get default view (window) for document
* @param element - Node to find window for
* @returns Window element
*/
function defaultView(element: SugarElement<Node>): SugarElement<Window>;Navigate up the DOM tree to find parents and ancestors.
/**
* Get immediate parent of element
* @param element - Element to get parent of
* @returns Parent element if it exists
*/
function parent(element: SugarElement<Node>): Optional<SugarElement<Node & ParentNode>>;
/**
* Get parent node (same as parent but different type)
* @param element - Element to get parent node of
* @returns Parent node if it exists
*/
function parentNode(element: SugarElement<Node>): Optional<SugarElement<Node>>;
/**
* Get parent element (skips non-element parents)
* @param element - Element to get parent element of
* @returns Parent element if it exists
*/
function parentElement(element: SugarElement<Node>): Optional<SugarElement<HTMLElement>>;
/**
* Get all parents up to document or optional root
* @param element - Starting element
* @param isRoot - Optional predicate to define root element
* @returns Array of parent elements from immediate parent to root
*/
function parents(element: SugarElement<Node>, isRoot?: (e: SugarElement<Node>) => boolean): SugarElement<Node>[];
/**
* Get offset parent for positioning calculations
* @param element - Element to find offset parent for
* @returns Offset parent element if found
*/
function offsetParent(element: SugarElement<HTMLElement>): Optional<SugarElement<HTMLElement>>;Usage Examples:
import { Traverse, SugarElement } from "@ephox/sugar";
const element = SugarElement.fromTag('span');
// Navigate to parent
const parentOpt = Traverse.parent(element);
parentOpt.each(parent => {
console.log('Parent tag:', parent.dom.tagName);
});
// Get all ancestors up to body
const ancestors = Traverse.parents(element, (e) => e.dom.tagName.toLowerCase() === 'body');
console.log('Ancestor chain:', ancestors.map(e => e.dom.tagName));
// Find offset parent for positioning
if (SugarNode.isHTMLElement(element)) {
const offsetParentOpt = Traverse.offsetParent(element);
offsetParentOpt.each(offsetParent => {
console.log('Offset parent:', offsetParent.dom.tagName);
});
}Navigate between sibling elements at the same level.
/**
* Get previous sibling element
* @param element - Element to find sibling for
* @returns Previous sibling if it exists
*/
function prevSibling(element: SugarElement<Node>): Optional<SugarElement<Node & ChildNode>>;
/**
* Get next sibling element
* @param element - Element to find sibling for
* @returns Next sibling if it exists
*/
function nextSibling(element: SugarElement<Node>): Optional<SugarElement<Node & ChildNode>>;
/**
* Get all previous siblings in document order
* @param element - Element to find siblings for
* @returns Array of previous siblings (nearest to furthest)
*/
function prevSiblings(element: SugarElement<Node>): SugarElement<Node & ChildNode>[];
/**
* Get all next siblings in document order
* @param element - Element to find siblings for
* @returns Array of next siblings (nearest to furthest)
*/
function nextSiblings(element: SugarElement<Node>): SugarElement<Node & ChildNode>[];
/**
* Get all siblings of element (excluding element itself)
* @param element - Element to find siblings for
* @returns Array of all sibling elements
*/
function siblings(element: SugarElement<Node>): SugarElement<Node>[];Access and navigate child elements with index-based operations.
/**
* Get all direct children of element
* @param element - Parent element
* @returns Array of child elements
*/
function children(element: SugarElement<Node>): SugarElement<Node & ChildNode>[];
/**
* Get child at specific index
* @param element - Parent element
* @param index - Zero-based index of child to retrieve
* @returns Child element at index if it exists
*/
function child(element: SugarElement<Node>, index: number): Optional<SugarElement<Node & ChildNode>>;
/**
* Get first child of element
* @param element - Parent element
* @returns First child if it exists
*/
function firstChild(element: SugarElement<Node>): Optional<SugarElement<Node & ChildNode>>;
/**
* Get last child of element
* @param element - Parent element
* @returns Last child if it exists
*/
function lastChild(element: SugarElement<Node>): Optional<SugarElement<Node & ChildNode>>;
/**
* Get total number of child nodes
* @param element - Parent element
* @returns Count of child nodes
*/
function childNodesCount(element: SugarElement<Node>): number;
/**
* Check if element has any child nodes
* @param element - Element to check
* @returns True if element has children
*/
function hasChildNodes(element: SugarElement<Node>): boolean;
/**
* Find index of element within its parent
* @param element - Element to find index for
* @returns Zero-based index within parent, if element has parent
*/
function findIndex(element: SugarElement<Node>): Optional<number>;Usage Examples:
import { Traverse, SugarElement } from "@ephox/sugar";
const list = SugarElement.fromTag('ul');
// ... add some list items ...
// Access children
const children = Traverse.children(list);
console.log(`List has ${children.length} items`);
// Get specific child
const firstItem = Traverse.firstChild(list);
const thirdItem = Traverse.child(list, 2);
// Navigate siblings
firstItem.each(item => {
const nextItem = Traverse.nextSibling(item);
nextItem.each(next => {
console.log('Next item found');
});
});
// Find element position
firstItem.each(item => {
const index = Traverse.findIndex(item);
console.log('Item index:', index.getOr(-1));
});Query elements using CSS selectors with scoping and filtering capabilities.
/**
* Find first element matching CSS selector within scope
* @param selector - CSS selector string
* @param scope - Element to search within
* @returns First matching element if found
*/
function one(selector: string, scope: SugarElement<ParentNode>): Optional<SugarElement<Element>>;
/**
* Find all elements matching CSS selector within scope
* @param selector - CSS selector string
* @param scope - Element to search within
* @returns Array of matching elements
*/
function all(selector: string, scope: SugarElement<ParentNode>): SugarElement<Element>[];
/**
* Check if element matches CSS selector
* @param element - Element to test
* @param selector - CSS selector to test against
* @returns True if element matches selector
*/
function is(element: SugarElement<Element>, selector: string): boolean;Usage Examples:
import { Selectors, SugarElement } from "@ephox/sugar";
const container = SugarElement.fromTag('div');
// ... populate with content ...
// Find specific elements
const button = Selectors.one('.submit-btn', container);
const inputs = Selectors.all('input[type="text"]', container);
// Check element matches
button.each(btn => {
if (Selectors.is(btn, '.primary')) {
console.log('Button is primary style');
}
});
// Find nested elements
const nestedSpans = Selectors.all('div > span', container);
console.log(`Found ${nestedSpans.length} direct span children of divs`);Predicate-based searching with ancestor/descendant operations.
/**
* Find ancestor element matching predicate
* @param element - Starting element
* @param predicate - Function to test elements
* @param isRoot - Optional root boundary function
* @returns First ancestor matching predicate
*/
function ancestor(
element: SugarElement<Node>,
predicate: (e: SugarElement<Node>) => boolean,
isRoot?: (e: SugarElement<Node>) => boolean
): Optional<SugarElement<Node>>;
/**
* Find descendant element matching predicate
* @param scope - Element to search within
* @param predicate - Function to test elements
* @returns First descendant matching predicate
*/
function descendant(
scope: SugarElement<Node>,
predicate: (e: SugarElement<Node>) => boolean
): Optional<SugarElement<Node>>;
/**
* Find all descendant elements matching predicate
* @param scope - Element to search within
* @param predicate - Function to test elements
* @returns Array of descendants matching predicate
*/
function descendants(
scope: SugarElement<Node>,
predicate: (e: SugarElement<Node>) => boolean
): SugarElement<Node>[];
/**
* Find closest ancestor (including self) matching predicate
* @param element - Starting element
* @param predicate - Function to test elements
* @param isRoot - Optional root boundary function
* @returns Closest element (including self) matching predicate
*/
function closest(
element: SugarElement<Node>,
predicate: (e: SugarElement<Node>) => boolean,
isRoot?: (e: SugarElement<Node>) => boolean
): Optional<SugarElement<Node>>;
/**
* Find sibling element matching predicate
* @param element - Starting element
* @param predicate - Function to test elements
* @returns First sibling matching predicate
*/
function sibling(
element: SugarElement<Node>,
predicate: (e: SugarElement<Node>) => boolean
): Optional<SugarElement<Node>>;Usage Examples:
import { PredicateExists, PredicateFilter, PredicateFind, SugarElement, SugarNode } from "@ephox/sugar";
const startElement = SugarElement.fromTag('span');
// Find ancestor with specific class
const form = Search.ancestor(startElement, (e) =>
SugarNode.isElement(e) && e.dom.classList.contains('form')
);
// Find descendant by tag name
const input = Search.descendant(form.getOrDie(), (e) =>
SugarNode.name(e) === 'input'
);
// Find all buttons in container
const buttons = Search.descendants(container, (e) =>
SugarNode.name(e) === 'button'
);
// Find closest table cell
const cell = Search.closest(startElement, (e) =>
['td', 'th'].includes(SugarNode.name(e))
);
// Find next form field sibling
const nextField = Search.sibling(input.getOrDie(), (e) =>
SugarNode.isElement(e) &&
['input', 'select', 'textarea'].includes(SugarNode.name(e))
);Navigate to specific positions within the DOM tree structure.
/**
* Navigate to deepest leaf element at specific offset
* @param element - Starting element
* @param offset - Character or child offset
* @returns Leaf element and adjusted offset
*/
function leaf(element: SugarElement<Node>, offset: number): ElementAndOffset<Node>;
interface ElementAndOffset<E> {
readonly element: SugarElement<E>;
readonly offset: number;
}Common predicates for element searching and filtering.
/**
* Predicate to match elements by tag name
* @param name - Tag name to match (case-insensitive)
* @returns Predicate function
*/
function byTag(name: string): (element: SugarElement<Node>) => boolean;
/**
* Predicate to match elements by CSS class
* @param className - CSS class name to match
* @returns Predicate function
*/
function byClass(className: string): (element: SugarElement<Node>) => boolean;
/**
* Predicate to match elements by attribute presence
* @param attribute - Attribute name to check for
* @returns Predicate function
*/
function byAttribute(attribute: string): (element: SugarElement<Node>) => boolean;
/**
* Predicate to match elements by attribute value
* @param attribute - Attribute name
* @param value - Attribute value to match
* @returns Predicate function
*/
function byAttributeValue(attribute: string, value: string): (element: SugarElement<Node>) => boolean;Usage Examples:
import { PredicateExists, PredicateFilter, PredicateFind, SugarElement } from "@ephox/sugar";
const container = SugarElement.fromTag('div');
// Use pre-built predicates
const buttons = Search.descendants(container, Predicates.byTag('button'));
const primaryBtns = Search.descendants(container, Predicates.byClass('btn-primary'));
const requiredFields = Search.descendants(container, Predicates.byAttribute('required'));
const emailInputs = Search.descendants(container, Predicates.byAttributeValue('type', 'email'));
// Combine predicates
const requiredEmailInputs = Search.descendants(container, (e) =>
Predicates.byTag('input')(e) &&
Predicates.byAttributeValue('type', 'email')(e) &&
Predicates.byAttribute('required')(e)
);Find elements using CSS selectors with comprehensive querying capabilities.
/**
* Check if element matches CSS selector
* @param element - Element to test
* @param selector - CSS selector to match against
* @returns True if element matches selector
*/
function is(element: SugarElement<Element>, selector: string): boolean;
/**
* Find first element matching selector within scope
* @param scope - Element to search within
* @param selector - CSS selector to match
* @returns First matching element, if found
*/
function one(scope: SugarElement<ParentNode>, selector: string): Optional<SugarElement<Element>>;
/**
* Find all elements matching selector within scope
* @param scope - Element to search within
* @param selector - CSS selector to match
* @returns Array of all matching elements
*/
function all(scope: SugarElement<ParentNode>, selector: string): SugarElement<Element>[];
/**
* Check if any element matching selector exists within scope
* @param scope - Element to search within
* @param selector - CSS selector to match
* @returns True if at least one match exists
*/
function exists(scope: SugarElement<ParentNode>, selector: string): boolean;
/**
* Filter elements by CSS selector
* @param elements - Elements to filter
* @param selector - CSS selector to match
* @returns Array of elements matching selector
*/
function filter(elements: SugarElement<Element>[], selector: string): SugarElement<Element>[];Calculate element positions and create addressable paths within DOM trees.
/**
* Generate address path from root to target element
* @param root - Root element to start from
* @param element - Target element to find path to
* @returns Array of indices representing path, if valid
*/
function generate(root: SugarElement<Node>, element: SugarElement<Node>): Optional<number[]>;
/**
* Follow address path from root element
* @param root - Root element to start from
* @param path - Array of indices to follow
* @returns Element at path location, if valid
*/
function follow(root: SugarElement<Node>, path: number[]): Optional<SugarElement<Node>>;
/**
* Check if element contains any matching child
* @param element - Container element
* @param predicate - Test function for children
* @returns True if any child matches predicate
*/
function has(element: SugarElement<Node>, predicate: ElementPredicate): boolean;
/**
* Check if element contains child matching selector
* @param element - Container element
* @param selector - CSS selector to match
* @returns True if any child matches selector
*/
function hasSelector(element: SugarElement<ParentNode>, selector: string): boolean;Transform-based searching and complex element location strategies.
/**
* Find element by transforming search criteria
* @param scope - Element to search within
* @param predicate - Transform function to apply
* @returns Transformed search result
*/
function scope<T>(scope: SugarElement<Node>, predicate: (e: SugarElement<Node>) => Optional<T>): Optional<T>;
/**
* Search using custom transformation function
* @param element - Starting element
* @param transform - Function to transform search
* @returns Transformed result of search
*/
function custom<T>(element: SugarElement<Node>, transform: (e: SugarElement<Node>) => Optional<T>): Optional<T>;// Position interface for leaf navigation
interface ElementAndOffset<E> {
readonly element: SugarElement<E>;
readonly offset: number;
}
// Common predicate type for element filtering
type ElementPredicate = (element: SugarElement<Node>) => boolean;
// Parent node types for selector queries
type ParentNode = Element | Document | DocumentFragment;