ponyfoo.com

Things you can do with native DOM

Fix

These are short-form “thoughts”, in addition to the usual longer-form articles in the blog. The goal is to publish one of these every weekday. I’d love to know what you think. You may send your questions to thoughts@ponyfoo.com. I’ll try to answer them over email and I may publish them here, with your approval. I also write thoughts about the current state of front-end development, and opinions on other people’s articles. You can use the form to the right (near the bottom in mobile) to subscribe via email.

I’ve stopped using jQuery years ago now. I learned a lot from jQuery, and from not using it anymore as well. Besides the things you can do with or without jQuery in terms of DOM selection, manipulation, and traversal (or AJAX, the sole reason people keep adding it to their projects nowadays – even though modules like xhr exist) – there’s unsurprisingly a ton of stuff you can easily do in plain native DOM API, without involving any libraries.

Some of them even enjoy wide browser support! This article explores getBoundingClientRect, elementFromPoint, and text selection with selectionStart and selectionEnd.

element.getBoundingClientRect

You could use getBoundingClientRect to get the current size of any DOM element, as well as it’s current position, relative to the viewport.

In the screenshot below I chose a random DOM element on the Elements tab of Dev Tools. Then I popped open the Console and used getBoundingClientRect on $0 – which is always bound to the last DOM element selected in the Elements tab.

rect.png
rect.png

In dragula, for example, I use getBoundingClientRect to figure out the absolute positioning of the elements that get dragged around by humans. A better example might be bullseye used in rome, horsey, and woofmark to place elements right below inputs, textareas, or even the text selection caret (although that one uses getSelection, polyfilled by seleccion, to get the selection offset).

The getBoundingClientRect method also has great browser support: all the way down to IE4. On IE8 and older, the often convenient width and height properties aren’t provided, but they could be inferred as right - left and bottom - top respectively.

document.elementFromPoint

Another cool piece of the web API that enjoys from broad browser support is elementFromPoint. It can find the topmost DOM element at any (x, y) point in the document. If the topmost element is inside an <iframe>, the <iframe> itself is returned. This method vastly simplifies the code in dragula, which needs to figure out what’s behind the element being dragged.

The code below hides the element being dragged using a class that sets display: none !important, ensuring that the subsequent elementFromPoint call returns the element that’s below. It surely doesn’t come up quite that often, but it’s still a nifty hack to leverage!

function getElementBehindPoint (point, x, y) {
  var old = point.className;
  point.className += ' gu-hide';
  var el = document.elementFromPoint(x, y);
  point.className = old;
  return el;
}

Besides drag and drop situations, this method is often used in integration tests using Selenium, when testers want to click a button that can be found in a precise point in the document. There’s probably a few more use cases, but there’s generally way cleaner ways to get references to DOM elements you care about.

selectionStart and selectionEnd

Whenever we modify user input we need to be careful enough to preserve their text selection. This comes up when we replace tokens such as at mentions (see the <textarea> example here), insert images or links in rich text-editing scenarios, and similar situations where you want to manipulate user input while it’s being entered.

Both of these properties can be found in input elements. You can read them directly, and you could also change their value, immediately updating the DOM as you’re used for other DOM-changing getters and setters like style properties such as el.style.display.

If you need support below IE9 you’d have to use something like sell, which leverages the TextRange API in those scenarios, and otherwise uses selectionStart and selectionEnd.

Have any questions or thoughts you’d like me to write about? Send an email to thoughts@ponyfoo.com. Remember to subscribe if you got this far!

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments (7)

Peter wrote

Stop saying plain JavaScript. You aren’t talking about plain JavaScript specifically.

Call it what it is: plain DOM. Don’t confuse people by associating every use of JS with the DOM, making it seem like the two things are one in the same.

The jQuery is not an abstraction of plain JavaScript, it is an abstraction of the plain DOM API.

If anything, underscore is an abstraction of plain JavaScript.

Šime Vidas wrote

I wanted to comment the same thing, but in a more polite manner, of course :P

Nicolas Bevacqua wrote

Fair enough, DOM API it is. Let’s dance to the joy of being correct!

Edwin Reynoso wrote

Hey can you check out NodeList.js, I really should write about it, and hopefully will soon, but perhaps you’d like to actually write about it. Once you see how useful it is.

Thanks.

Edwin

Kevin Jantzer wrote

Awesome! Thanks for this. I knew about getBoundingClientRect (although I always forget about it), but had never heard of elementFromPoint. That will be helpful in the future.

PGJ wrote

“Some of them even enjoy wide browser support!” - and that pretty much sums up why people still use jQuery instead…

JSco wrote

Agreed - cross browser compatibility - the only reason I use jQuery