Corresponding Node Across PagesLoading saved progress…

Corresponding Node Across Pages

You have two DOM trees that are structural mirrors of each other: same shape, same number of children at every level, same order — but their text and attributes may differ (think the same page rendered in two languages, or before and after a translation pass). Given a node somewhere inside the first tree, find the node in the second tree that sits in the exact same spot. This is a real problem behind tools that sync a selection, a highlight, or a cursor position from one rendered copy of a document to another.

The key insight: identify a node by its position — the path of child indices from the root down to it — not by its tag, id, or text, because the mirror may contain repeated or identical elements.

Signature

function correspondingNodeAcrossPages(
  rootA: Node, // root of the first tree
  rootB: Node, // root of the second tree (a structural mirror of rootA)
  nodeA: Node, // a node somewhere inside rootA
): Node; // the node in rootB at the same path from the root

Index positions are taken over childNodes (so text nodes count toward the index), making the mapping an exact structural mirror. If nodeA === rootA, return rootB.

Examples

const a = document.createElement('div');
a.innerHTML = '<ul><li>one</li><li>two</li><li>three</li></ul>';
const b = document.createElement('div');
b.innerHTML = '<ul><li>uno</li><li>dos</li><li>tres</li></ul>';

const secondLiA = a.querySelectorAll('li')[1]; // <li>two</li>
correspondingNodeAcrossPages(a, b, secondLiA);
// → <li>dos</li>  (the 2nd li in b, NOT the first)
// nodeA is the root itself
correspondingNodeAcrossPages(a, b, a); // → b

// a text node maps to the corresponding text node
const textA = a.querySelector('li').childNodes[0]; // the "one" text node
correspondingNodeAcrossPages(a, b, textA); // → the "uno" text node

Notes

  • Match by path, not by content. The trees can hold repeated or identical elements (three identical <li>). Matching by tag, id, or text would return the wrong sibling; only the position is reliable.
  • Use childNodes, not children. childNodes includes text and comment nodes, so indices count every node. This keeps the mapping an exact structural mirror and lets you map text nodes too.
  • The trees are true mirrors. Same shape at every level, same child order. You do not need to handle trees of different shapes.
  • Root maps to root. If nodeA is rootA, the answer is rootB — there is no path to walk.
  • Return the live reference. Return the actual node from rootB, not a clone or a copy.
Loading editor…