2

I'm working on a web-based system similar to https://visitortracking.com/, where different businesses can join as tenants. Once they join, they can create campaigns for their websites.

Before creating a campaign, they must first generate tracking scripts for their individual websites and embed these scripts into their sites. After that, they can create campaigns. While setting up a campaign, I want them to specify the elements on which a conversion will be counted.

To make this process easier, I'm creating a visual selector tool, where users can enter their website URL and visually select any element of their choice (e.g., "Add to Cart" or "Submit" buttons).

Since websites with complex structures make it difficult to identify HTML elements separately, I need a way to generate an accurate and unique CSS selector when an element is clicked.

I have created a function for this, but I'm not sure if it covers all edge cases. I would love to know if anyone has done similar work before or if there is a better alternative approach.

Keep in mind that these websites can be built using any tool (wordpress, custom html css, Shopify), so I don't have a way to share the exact HTML structure with you.

  function generateQuerySelector(el) {
    if (!el || el.tagName.toLowerCase() === 'html') return 'HTML';

    const path = [];
    while (el && el.nodeType === Node.ELEMENT_NODE) {
      let selector = el.tagName.toLowerCase();

      // Add ID if available
      if (el.id) {
        selector += '#' + el.id;
        path.unshift(selector);
        break; // IDs are unique, so we can stop here
      }

      // Add class names if available
      if (el.className && typeof el.className === 'string') {
        const classes = el.className.split(/\s+/).filter(Boolean);
        if (classes.length > 0) {
          selector += '.' + classes.join('.');
        }
      }

      const parent = el.parentNode;
      if (parent) {
        const siblings = Array.from(parent.children).filter(
          child => child.tagName.toLowerCase() === el.tagName.toLowerCase()
        );
        if (siblings.length > 1) {
          const index = siblings.indexOf(el) + 1;
          selector += `:nth-child(${index})`;
        }
      }
      path.unshift(selector);
      el = el.parentNode;
    }

    return path.join(' > ');
  }
5
  • 1
    "...I need a way to generate a reliable CSS selector that remains uniq and accurate." That's a misconception many people have when they know enough to write working code but not enough to know that there's 100 different ways to accomplish the same goal. You'll need to post the relevant HTML and CSS with the JS as a minimal reproducible example (hint: click the brackets button <>). Commented Mar 10 at 9:09
  • 1
    Seems like an XY problem. What exactly are you going to do with the return value of generateQuerySelector()? As an alternative, you might be able to generate an xpath Commented Mar 10 at 9:37
  • I need a way to generate a reliable CSS selector - why? Knowing why may help us provide an alternative solution. Assuming your sites are built dynamically from a db store, you could give each element a guid as you store it in the DB then use data-guid=... then you can access that element via its data attribute in css with [data-guid='...'] Commented Mar 10 at 9:39
  • "IDs are unique, so we can stop here" - they should be unique but, as seen many, many times here, that rule is often ignored. In such cases how would your code fare? Commented Mar 10 at 10:25
  • Related to: Javascript get XPath of a node Commented Mar 10 at 12:23

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.