43

I want to write a browser (Chrome/FF) extension that needs to select an element on a web page. I would like it to behave like Firebug's element inspector does. You click the inspect arrow and you can then hover/highlight elements. When you click on the element you want, the element is inspected. I'm just interested in the code to allow a user to select an element - not in actually inspecting it or anything similar.

Because I'm writing an extension, it might be nice if you could provide non-jQuery/Prototype/etc.. code so I don't have to distribute that.

Ashit Vora
2,9222 gold badges29 silver badges41 bronze badges
asked Mar 8, 2010 at 7:07
2
  • The easiest way is to check Firebug's code. If you've installed firebug, you can find the code inside the firefox profile folder. The default location in my linux machine ~/.mozilla/firefox/random-chars.default/extensions/[email protected]/content/firebug In Vista it is something like: C:\Users\<user-name>\AppData\Roaming\Mozilla\Firefox\Profiles\random-chars.default\extensions\[email protected]\content\firebug Commented Mar 8, 2010 at 7:26
  • Well, it sounded like a great idea--at first. Then I went and looked at the code and there's 50+ files all of reasonable size. I don't even know where to begin and moreso, I don't know what to copy/paste/modify. So, sadly this is definitely not the "easiest" thing. I will probably home-brew something unless I find other solutions or others respond. Commented Mar 9, 2010 at 6:22

10 Answers 10

26

I have recently required such a feature for a project I was working on, turned out that I had to use 4 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.

answered Sep 7, 2013 at 16:26
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! Great instructions and I like the slide effect in the demo!
Brilliant explanation!
20

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

answered Oct 20, 2012 at 23:11

Comments

14

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.

answered Aug 30, 2010 at 10:44

1 Comment

this does not work when you want to highlight images <img/>
13

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.

answered Apr 6, 2019 at 11:49

2 Comments

Looked at a bunch and this one is the simplest and cleanest
Adjustments to emulate Chrome inspector: hoverBox.style.zIndex = "9999"; hoverBox.style.opacity = .5; hoverBox.style.pointerEvents = "none";
7
answered Mar 13, 2010 at 16:34

2 Comments

Can you the code with us please? I want to do something similar
I'm doing a similar thing in one of my projects but I need to a little bit to this. After the element is selected, I want to get the Unique selector for that element. Any idea how to do that? Right now I'm hacking it... If the selected element has ID attribute, we are good. Else I check for class and find the index of the selected element with similar class and if it doesn't then I take the Tag name repeat the same process. But this method is totally not reliable. Is there a better alternative?
4

Here is a library that written in pure javascript as an alternative.

TheRoom JS: https://github.com/hsynlms/theroomjs

// theroom information template for target element
var template="";
template += "<div id=\"theroom-info\">";
template += " <span id=\"theroom-tag\"><\/span>";
template += " <span id=\"theroom-id\"><\/span>";
template += " <span id=\"theroom-class\"><\/span>";
template += "<\/div>";
template += "";
template += "<style>";
template += " #theroom-info {";
template += " position: fixed;";
template += " bottom: 0;";
template += " width: 100%;";
template += " left: 0;";
template += " font-family: \"Courier\";";
template += " background-color: #ffffff;";
template += " padding: 10px;";
template += " color: #333333;";
template += " text-align: center;";
template += " box-shadow: 0px 4px 20px rgba(0,0,0,0.3);";
template += " }";
template += "";
template += " #theroom-tag {";
template += " color: #C2185B;";
template += " }";
template += "";
template += " #theroom-id {";
template += " color: #5D4037;";
template += " }";
template += "";
template += " #theroom-class {";
template += " color: #607D8B;";
template += " }";
template += "<\/style>";
var options = {
 template: template,
 showInfo: true
};
// initialize
theRoom.start(options);

codepen demo

answered Apr 13, 2018 at 22:28

Comments

3

There was a similar question asked on Stackoverflow and it had lots of good answers: Does anyone know a DOM inspector javascript library or plugin?

For those who are looking for a quick and dirty solution:

http://userscripts.org/scripts/review/3006 is the easiest. Just put the code within <script></script> tags and you are good to go.

https://github.com/josscrowcroft/Simple-JavaScript-DOM-Inspector/blob/master/inspector.js is slightly better and still very easy to integrate in.

For a more sophisticated element inspector, you might want to check out the SelectorGadget as pointed by Udi. The inspector selection code is in http://www.selectorgadget.com/stable/lib/interface.js

answered Oct 12, 2011 at 15:02

1 Comment

The Simple Javascript DOM inspector looks very promising and a simple library.
2

Also check this one out:

http://rockingcode.com/tutorial/element-dom-tree-jquery-plugin-firebug-like-functionality/

I found it pretty insightful.. and there's a demo here:

http://rockingcode.com/demos/elemtree/

Hope this helps.

phreakhead
15.4k5 gold badges42 silver badges42 bronze badges
answered Mar 20, 2013 at 20:06

Comments

2

A very basic implementation can be done very easily without jQuery using .onmouseover and e.target:

var last,
 bgc;
document.onmouseover = function(e) {
 var elem = e.target;
 if (last != elem) {
 if (last != null) {
 last.classList.remove("hovered");
 }
 last = elem;
 elem.classList.add("hovered");
 }
}

With the CSS below if you want the children to change background as well:

.hovered,
.hovered * {
 cursor: pointer;
 color: black;
 background-color: red;
}

Demo


If you want to select elements only near the edges (or select the parent near the edges and the element itself everywhere else) you could use .getBoundingClientRect.

var last;
window.addEventListener("mousemove", function(e) {
 if(last) {
 last.style.background = ''; // empty is enough to restore previous value
 }
 var elem = e.target;
 if(elem === document.body || elem === document.documentElement) {
 return;
 }
 var bb = elem.getBoundingClientRect();
 var xr = e.pageX - bb.left; // x relative to elem
 var yr = e.pageY - bb.top; // y relative to elem
 var ew = 10; // edge width
 if(
 xr <= ew
 || xr >= bb.width - ew
 || yr <= ew
 || yr >= bb.height - ew
 ){
 elem.style.background = 'red';
 last = elem;
 }
});

Paired with some borders, this can be pretty usable for selection. Demo

answered May 19, 2016 at 17:22

Comments

0

What you need to do is to create 4 elements for the highlighting. They will form an empty square, and so your mouse events are free to fire. This is similar to this overlay example I've made.

The difference is that you only need the four elements (no resize markers), and that the size and position of the 4 boxes are a bit different (to mimick the red border). Then you can use event.target in your event handler, because it gets the real topmost element by default.

Another approach is to hide the exra element, get elementFromPoint, calculate then put it back.

They're faster than light, I can tell you. Even Einstein would agree :)

1.) elementFromPoint overlay/borders - [Demo1] FF needs v3.0+

var box = $("<div class='outer' />").css({
 display: "none", position: "absolute", 
 zIndex: 65000, background:"rgba(255, 0, 0, .3)"
}).appendTo("body");
var mouseX, mouseY, target, lastTarget;
// in case you need to support older browsers use a requestAnimationFrame polyfill
// e.g: https://gist.github.com/paulirish/1579671
window.requestAnimationFrame(function frame() {
 window.requestAnimationFrame(frame);
 if (target && target.className === "outer") {
 box.hide();
 target = document.elementFromPoint(mouseX, mouseY);
 }
 box.show(); 
 if (target === lastTarget) return;
 lastTarget = target;
 var $target = $(target);
 var offset = $target.offset();
 box.css({
 width: $target.outerWidth() - 1, 
 height: $target.outerHeight() - 1, 
 left: offset.left, 
 top: offset.top 
 });
});
$("body").mousemove(function (e) {
 mouseX = e.clientX;
 mouseY = e.clientY;
 target = e.target;
});

2.) mouseover borders - [Demo2]

var box = new Overlay();
$("body").mouseover(function(e){
 var el = $(e.target);
 var offset = el.offset();
 box.render(el.outerWidth(), el.outerHeight(), offset.left, offset.top);
});​
/**
 * This object encapsulates the elements and actions of the overlay.
 */
function Overlay(width, height, left, top) {
 this.width = this.height = this.left = this.top = 0;
 // outer parent
 var outer = $("<div class='outer' />").appendTo("body");
 // red lines (boxes)
 var topbox = $("<div />").css("height", 1).appendTo(outer);
 var bottombox = $("<div />").css("height", 1).appendTo(outer); 
 var leftbox = $("<div />").css("width", 1).appendTo(outer);
 var rightbox = $("<div />").css("width", 1).appendTo(outer);
 // don't count it as a real element
 outer.mouseover(function(){ 
 outer.hide(); 
 }); 
 /**
 * Public interface
 */
 this.resize = function resize(width, height, left, top) {
 if (width != null)
 this.width = width;
 if (height != null)
 this.height = height;
 if (left != null)
 this.left = left;
 if (top != null)
 this.top = top; 
 };
 this.show = function show() {
 outer.show();
 };
 this.hide = function hide() {
 outer.hide();
 }; 
 this.render = function render(width, height, left, top) {
 this.resize(width, height, left, top);
 topbox.css({
 top: this.top,
 left: this.left,
 width: this.width
 });
 bottombox.css({
 top: this.top + this.height - 1,
 left: this.left,
 width: this.width
 });
 leftbox.css({
 top: this.top, 
 left: this.left, 
 height: this.height
 });
 rightbox.css({
 top: this.top, 
 left: this.left + this.width - 1, 
 height: this.height 
 });
 this.show();
 }; 
 // initial rendering [optional]
 // this.render(width, height, left, top);
}
answered May 31, 2015 at 8:15

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.