Given a root node and target node, generate a CSS selector from the root to the target. Provide an exact selection.
Example
Input: <div id="root"> <article>Prepare for interview</article> <section> on <p> <span> Learnersbucket <button>click me!</button> <button id="target">click me!</button> </span> </p> </section> </div> Output: "div[id='root'] > section:nth-child(2) > p:nth-child(1) > span:nth-child(1) > button:nth-child(2)"
It is quite straightforward to generate the CSS selector, all we have to do is start from the target and trace back to the root (parent).
- Use a while loop and keep iterating till we have found the root of the target.
- In each iteration get the index of the current child in its immediate parent to decide the nth-child position.
- At the end, add the roots tag name. The selector will begin from this.
const generateSelector = (root, target) => { // trace the selector from target to root const selectors = []; // iterate till root parent is found while (target !== root) { // get the position of the current element as its parent child // add one to it ass CSS nth-child is not like array, it starts from 1. const nthChild = Array.from(target.parentNode.children).indexOf(target) + 1; const selector = `${target.tagName.toLowerCase()}:nth-child(${nthChild})`; // add the selector at the front selectors.unshift(selector); // move to the parent target = target.parentNode; } // add the root's tag name at the beginning // with your preferred selector // id is used here selectors.unshift(`${target.tagName.toLowerCase()}[id="${target.id}"]`); // join the path of the selector and return them return selectors.join(' > '); }
Input: <div id="root"> <article>Prepare for interview</article> <section> on <p> <span> Learnersbucket <button>click me!</button> <button id="target">click me!</button> </span> </p> </section> </div> const root = document.getElementById("root"); const target = document.getElementById("target"); console.log(generateSelector(root, target)); Output: "div[id='root'] > section:nth-child(2) > p:nth-child(1) > span:nth-child(1) > button:nth-child(2)"