DEV Community

Shweta Kale
Shweta Kale

Posted on

DOM Question #8 - closest interactive element

Find the closest interactive element (button, input, link) to a given DOM node.

To find closest element we can use element.closest so it will be something like

const closestInteractiveEl = (node) => {
 return node.closest('button, a, input');
}
Enter fullscreen mode Exit fullscreen mode

But this will only return el if current node or parent nodes are interactive. Because closest traverse till root from current element and returns if selector matches.

According to question we need to find closest interactive element. This can be sibling, children or ancestor.

We can solve this by getting all interactive nodes and their distance from current node. We will return element who has minimum distance from current node. If we have to get distance by traversing DOM this will be a complex problem as calculating distance between two nodes is time consuming task. Instead we will find visual proximity, which means that we will find distance between current and interactive node when they are rendered on the screen.

Image description

const findClosestIinteractiveElement = ()=> {
  const interactiveSelectors = ['button', 'a', 'input', '[role="button"]', '[role="link"]','[role="checkbox"]',
    '[role="radio"]'];

  const interactiveElements = Array.from(document.querySelectorAll(interactiveSelectors.join(',')))
}

if(interactiveElements.length===0){
 return {element: null, distance: Infinity};
}

 // Get the position of the reference node
  const nodeRect = node.getBoundingClientRect();
  const nodeCenter = {
    x: nodeRect.left + nodeRect.width / 2,
    y: nodeRect.top + nodeRect.height / 2
  };

let closestElement = null;
let shortestDistance = Infinity;

// finding distance between given and interactive node.
for(const interactiveElement of interactiveElements){
  if(node===interactiveElement || node.contains(interactiveElement)){
    return {node: element, distance: 0}
  }

  const elementRect = interactiveElement.getBoundingClientRect();
  const elementCenter = {
    x: elementRect.left + elementRect.width/2,
    y: elementRect.top + elementRect.height/2
  };

// calculate Euclidian distance
  const distance = Math.sqrt(Math.pow(elementCenter.x-nodeCenter.x, 2) + Math.pow(elementCenter.y - nodeCenter.y, 2))

  if(distance < shortestDistance){
   shortestDistance = distance;
   closestElement = interactiveElement;
  }
}

return {element: closestElement, distance: shortestDistance};

Enter fullscreen mode Exit fullscreen mode

AWS GenAI LIVE image

How is generative AI increasing efficiency?

Join AWS GenAI LIVE! to find out how gen AI is reshaping productivity, streamlining processes, and driving innovation.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

Best practices for optimal infrastructure performance with Magento

Running a Magento store? Struggling with performance bottlenecks? Join us and get actionable insights and real-world strategies to keep your store fast and reliable.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️