DEV Community

Cover image for DOM elements with ID's are global variables
Andrew Buntine
Andrew Buntine

Posted on

DOM elements with ID's are global variables

So, here is something weird.

Yesterday I was refactoring some code and came across something akin to this:

const logo = document.getElementById("brand")

brand.style.top = 0
Enter fullscreen mode Exit fullscreen mode

At no point in the codebase was a variable named brand defined. And so any sane observer would expect that the preceding snippet would result in a runtime error -- assuming there was not something like a linter available that would have picked up on it (and the fact that logo was being defined but never used) first.

I started having one of those moments that we all dread: I was looking at some code that could not possibly have ever worked. Yet, there it was. Working. I sank into my chair, not sure to make of what I was seeing.

In fact, the only other place I could see the word "brand" in the entire application was in the HTML document upon which this Javascript was being executed (yes, some websites still send HTML over the wire).

So I changed it:

<div id="brand_foo"> ... </div>
Enter fullscreen mode Exit fullscreen mode

And then, lo and behold, the code instantly started causing a runtime error. Wait. No way... The browser is surely not pre-defining a global variable for each DOM element with an ID attribute. Right?

Wrong! It does. I've looked at this code in most major browsers and mobile devices and not one of them complained.

Don't believe me? You can try it yourself right now. Press F12 (or otherwise Right Click -> Inspect), find an element with an ID, and then evaluate that ID at the console REPL.

What about IDs such as "brand-name" that don't conform to Javascript's grammar? Surely they are ignored? Nope:

window["brand-name"]  // --> <div id="brand-name">
Enter fullscreen mode Exit fullscreen mode

I have no idea how well known this is. I certainly did not know about it but, admittedly, I haven't spent a lot of time in the browser in many years. I've reached out to all of the frontend developers I know and none of them knew about this either.

As it turns out, the HTML specification actually documents this functionality. Although it seems major browsers are not implementing it uniformly at all. If you define more than one element with the same ID (you evil person), then Chrome will actually return an array of Element objects whilst Firefox returns the first element it saw. And neither browsers define global variables based on the name attribute on elements like img and a.

Should I make use of this?

No. Please, no. Imagine how confusing this could get if you were dealing with many DOM elements in a non-trivial codebase and none of them were being defined anywhere visible to the programmer. Or imagine if you go all-in and then one day a major browser decides this is insanity and disables it!

The only place I can see this being of use would be in the REPL whilst debugging. But, still, it's kind of cool in a never-do-this kind of way.

Header image originally from http://www.classichorrorcampaign.com

Oldest comments (35)

Collapse
 
rachelcarvalho profile image
Rachel Carvalho

People who have had contact with front-end code for long enough will remember that this is how people used to write Javascript 🤢. I'm talking about way back when websites were developed for IE 6 and did not run well on the new Firefox browser because of so much non standard html, css and js there was.

Collapse
 
maximeeuziere profile image
xem

Hi,

I studied this behavior on my blog, if you're interested:

xem.github.io/articles/#implicitge...

Collapse
 
loderunner profile image
Charles Francoise

Nicely spotted! Although we're supposed to think of "global" variables as Bad™, I think there's a definite case to be made why this is actually Not So Bad™.

An DOM element with an ID, by definition, can be referenced from any context. Semantically, it is pretty akin to a "global variable". Also, one of the guarantees of DOM elements with IDs is that they have a speedy lookup (O(1) if possible).

With these assumptions, it makes sense that a naive implementation would store them somewhere in the global scope. Would it have been better to store them in a member object, such as window.elementsWithIds? Probably, but quite marginally. And as Rachel Carvalho pointed out, not necessarily worth breaking legacy applications.

Great catch, though. I think all front-end developers should be aware of this, if only to avoid mind-bending bugs like the one you mentioned and to understand the inner workings of the target machine (aka "The Browser").

--

EDIT: I'm quite new at Javascript so I'm bound to make some errors.

My previous argument doesn't hold in face of this little snippet.

<html>
<body>
<div id="crypto">Crypto</div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode
> document.getElementById('crypto')
<div id=​"crypto">​Crypto​</div>​

> window.crypto
Crypto {subtle: SubtleCrypto}
Enter fullscreen mode Exit fullscreen mode

Naming your element after a built-in Window property does not overwrite the property, but you can still perform a lookup by ID on the document. So there's obviously a better mechanism already in place.

The fact that IDs create global objects is probably only to maintain backwards compatibility, as Rachel pointed out.

Collapse
 
stephenhand profile image
Stephen Hand

Dom elements referenced by ID are global variables and have the same drawbacks as other global variables. I've seen more than supposedly 'reuseable component' break as soon as you tried to add a second instance of it to a page because it's referencing its internal DOM elements by ID...

Collapse
 
andreujuanc profile image
Juan C. Andreu

Saw this behavior in cordova-plugin-splashscreen where they used the element's id without any kind of check, assuming it will exist.

Problem was my application removed that element and their code didn't check for it's existence.

Good post.

Collapse
 
rutinerad profile image
Samuel Lindblom

Yep, I knew about it, the outcome of the exact same "looking at some code that could not possibly have ever worked [...], not sure to make of what I was seeing".

Collapse
 
maxart2501 profile image
Massimo Artizzu

Yes, that's actually a very old behaviour. As old as Internet Explorer... 5, maybe?
It's been kept just for compatibility reasons. Just don't ever, ever rely on that, because it's really bad :(

Collapse
 
klabranche profile image
Kevin LaBranche

I've been doing web dev for a long time and didn't know about this. lol on myself but not something I plan on using either.

Collapse
 
thebohman profile image
Christopher Bohman

The best part about knowing this? I've done some things in a dev environment expecting an error to be thrown.. and then it doesn't. Then I get confused. Then I doubt my own existence. When there's an explanation, less of this happens.

Collapse
 
tomas2387 profile image
Tomás Prado Bley

You just found the Pandora box nobody have seen! lol.
Anyway, This is quite ugly and I hope nobody uses it. I don't see any benefits, only to make a nice place for bugs to hide.

Collapse
 
atrandafir profile image
Alexandru Trandafir

I did noticed this some time ago too!! :D