An HTML element id is a global variable
By Flavio Copes
Did you know an HTML element with an id attribute is automatically exposed as a global JavaScript variable you can reference by name? Here is how it works.
Little relatively unknown fact: if you have an id attribute on an element, the browser exposes that element as a global JavaScript variable with the same name.
Say you have this button:
<button id="subscribe">Subscribe</button>
You can reference it in JavaScript without any lookup:
subscribe.onclick = () => {
console.log('clicked')
}
No getElementById(), no querySelector(). The variable subscribe just exists, and it holds the DOM element.
This is called named access on the window object. The element becomes a property of window, so subscribe and window.subscribe are the same thing.
It works with forms too. Child elements with a name attribute can be referenced through the form:
<form id="signup">
<input name="email">
</form>
signup.email.value = 'flavio@flaviocopes.com'
Why does this exist?
This behavior comes from the early days of the web. Internet Explorer introduced it, other browsers copied it for compatibility, and eventually it was written into the HTML spec. Too many old sites depended on it to ever remove it.
So it’s standard behavior, in every browser, and it’s not going away.
Should you use it?
I wouldn’t rely on it, for one main reason: the global namespace is crowded.
If your id collides with an existing window property, the element loses. An element with id="location" doesn’t create a variable holding the element, because window.location already exists. Same for name, history, top, and many others.
Your own code can shadow it too. Declare a variable called subscribe anywhere in scope, and the element reference is gone. Nothing warns you. The code that depended on the global just breaks.
The fix is to be explicit:
const subscribe = document.querySelector('#subscribe')
Same result, but now the lookup is visible in the code, and no naming collision can silently change what the variable holds.
Maybe not your favorite API, but it’s a thing. And knowing it exists helps you decode the occasional codebase (or code golf trick) that uses it.