Javascript: Let user select an HTML element like Firebug?

I wrote an implementation of this using jQuery as a component of another project. The source and documentation are available here: https://github.com/andrewchilds/jQuery.DomOutline


I have recently required such a feature for a project I was working on, turned out that I had to use for sides to create a box because otherwise the event.target when you move the mouse would end up being the selector, and if I were to use z-index: -1 it would be a bit fishy when you have a lot of elements that overlap...etc.

Here is a version that I have converted from my project for your benefit, it involves jQuery but it is extremely simple to convert to vanilla as only the mousemove & css methods from jQuery are used.

Step by step instructions.

First create the 5 HTMLElements that are required.

<div id="selector">
    <div id="selector-top"></div>
    <div id="selector-left"></div>
    <div id="selector-right"></div>
    <div id="selector-bottom"></div>
</div>

Secondly create a mousemove event on the document (or your container)

$(document).mousemove(function(event) { ... });

Then inside the mousemove we will do some basic checking to prevent selecting the HTML, BODY, selector

var id = event.target.id, tagName = event.target.tagName;

if(id.indexOf('selector') !== -1 || tagName === 'BODY' || tagName === 'HTML') {
   return;
} 

Then we need to create a object to store our elements like so.

var elements = {
    top: $('#selector-top'),
    left: $('#selector-left'),
    right: $('#selector-right'),
    bottom: $('#selector-bottom')
};

After that we store some variables that hold some information about the target element like so.

var $target = event.target;
    targetOffset = $target.getBoundingClientRect(),
    targetHeight = targetOffset.height,
    targetWidth  = targetOffset.width;

Then all we do is calculate the position & height for all 4 sides of the selector like so.

elements.top.css({
    left:  (targetOffset.left - 4),
    top:   (targetOffset.top - 4),
    width: (targetWidth + 5)
});

elements.bottom.css({
    top:   (targetOffset.top + targetHeight + 1),
    left:  (targetOffset.left  - 3),
    width: (targetWidth + 4)
});

elements.left.css({
    left:   (targetOffset.left  - 5),
    top:    (targetOffset.top  - 4),
    height: (targetHeight + 8)
});

elements.right.css({
    left:   (targetOffset.left + targetWidth + 1),
    top:    (targetOffset.top  - 4),
    height: (targetHeight + 8)
});

All of the +aFewPixels is just a little optimization so that there is like 2px gap in between the selector and the target.

For the CSS this is what I have come up with.

#selector-top, #selector-bottom {
    background: blue;
    height:3px;
    position: fixed;
    transition:all 300ms ease;
}

#selector-left, #selector-right {
    background: blue;
    width:3px;
    position: fixed;
    transition:all 300ms ease;
}

The transition gives the selector a very nice sliding effect.

Try out a demo http://jsfiddle.net/rFc8E/9/

Note: This also works for transform: scale(2); eg. when a element is scaled in size.

Edit: I've just updated this, I noticed that the elements object was inside the event handler, I've moved it outside in the demo, this is quite an important performance improvement because now, the elements object is only created once instead of Hundreds of Thousands if not millions of times inside the mousemove event.


HTML Element Picker (Vanilla JS)

Pick and highlight any HTML element on a page with only Vanilla JS! Tested in Chrome, FF, and Opera, doesn't work in IE.

How it works:

What you need is actually very simple. You can just create an empty div box with a background in JS and move it around to highlight on top of hovered elements. Here's the JS code:

const hoverBox = document.createElement("div");
console.log("hoverBox: ", hoverBox);
hoverBox.style.position = "absolute";
// change to whatever highlight color you want
hoverBox.style.background = "rgba(153, 235, 255, 0.5)";
// avoid blocking the hovered element and its surroundings
hoverBox.style.zIndex = "0";
document.body.appendChild(hoverBox);
let previousTarget;
document.addEventListener("mousemove", (e) => {
    let target = e.target;
    if (target === hoverBox) {
        // the truely hovered element behind the added hover box
        const hoveredElement = document.elementsFromPoint(e.clientX, e.clientY)[1];
        if (previousTarget === hoveredElement){
            // avoid repeated calculation and rendering
            return;
        } else{
            target = hoveredElement;
        }
    } else{
        previousTarget = target;
    }
    const targetOffset = target.getBoundingClientRect();
    const targetHeight = targetOffset.height;
    const targetWidth = targetOffset.width;
    // add a border around hover box
    const boxBorder = 5;
    hoverBox.style.width = targetWidth + boxBorder * 2 + "px";
    hoverBox.style.height = targetHeight + boxBorder * 2 + "px";
    // need scrollX and scrollY to account for scrolling
    hoverBox.style.top = targetOffset.top + window.scrollY - boxBorder + "px";
    hoverBox.style.left = targetOffset.left + window.scrollX - boxBorder + "px";
});

See Demo
I also made an npm package for the element picker with many more user configurations like background color, border width, transition, etc. Here's the GitHub page.


One simple way to do it is to use an outline instead of a border:

.highlight { outline: 4px solid #07C; }

Just add and remove that class to any element you want to select/deselect (code below is not properly tested):

document.body.addEventListener("mouseover", function(e) {
    e.stopPropagation();
    e.target.addEventListener("mouseout", function (e) {
        e.target.className = e.target.className.replace(new RegExp(" highlight\\b", "g"), "");
    });
    e.target.className += " highlight";
});

Since you are using an outline, (which is supported by Chrome) instead of a border, elements will not jump around. I'm using something similar in my EasyReader Extension.