or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

dom.mdevents.mdindex.mdnode.mdproperties.mdsearch.mdselection.mdtag.mdview.md
tile.json

search.mddocs/

DOM Traversal and Search

Tree traversal, element querying, and hierarchical navigation utilities with type-safe parent/child relationships, CSS selector support, and comprehensive search capabilities.

Capabilities

DOM Tree Traversal

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>;

Parent and Ancestor Navigation

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);
  });
}

Sibling Navigation

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>[];

Child Navigation

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));
});

CSS Selector Queries

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`);

Advanced Element Search

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))
);

Position-Based Navigation

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;
}

Pre-built Search Predicates

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)
);

CSS Selector Operations

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>[];

Element Address and Location

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;

Advanced Search Patterns

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>;

Types

// 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;