Beware of id and name attribute mixups when using getElementById in Internet Explorer

It is probably old news to the JavaScript experts among you, but since I recently ran into this problem myself and pulled my hair in frustration before a coworker hinted at the solution I think it’s worth mentioning:

When using getElementById to get a reference to an element via the id attribute, Internet Explorer for Windows (and some versions of Opera) will also match an element whose name attribute contains the same value.

This doesn’t always cause any noticeable problems since in most cases you’re not all that likely to have identical name and id values for different elements, but when it does happen it can lead to errors that are very hard to debug.

Here is a simple example HTML document that is susceptible to this problem:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"

"http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

<meta name="description" content="A brief description of the content on this page.">

<title>The name and id attributes in IE</title>

</head>

<body>

<div id="description">

<p>A description of something.</p>

</div>

</body>

</html>

Now imagine that you want to use JavaScript to do something to div#description. For simplicity’s sake, let’s say you write the following script that hides the div element by setting its display CSS property to none when the page is loaded:

function hideIt() {

var obj = document.getElementById('description');

obj.style.display = 'none';

}

window.onload = hideIt;

That works as expected everywhere except in Internet Explorer, where nothing happens. The reason for that is that in IE, getElementById finds and returns the meta element whose name attribute has the value description before it gets to the div element.

Thanks for the kind words. Unfortunately, though, you will experience the same problems with DOMAssistant.

A while back I didn’t code a workaround out of avoiding any possible performance hit, and a bit naively being under the impression that every web developer should know and control the uniqueness of IDs and don’t mix them with names.

However, in reality, with several developers working on the same code and also code coming from a source which you can’t control, these things will occur from time to time.

Therefore, in the upcoming version of DOMAssistant, this has been addressed (due to be released in a week or two).

To analyze the problem, it doesn’t seem to affect all kinds of elements, and it depends on the order of the elements in the source order. This will cause the error:

<input type=”text” id=”some_name” value=”Correct”>

<input type=”text” name=”some_name” value=”WRONG”>

While this won’t:

<input type=”text” name=”some_name” value=”WRONG”>

<input type=”text” id=”some_name” value=”Correct”>

As a sidenote, this is only the tip of the iceberg when it comes to weirdness in IE. I recommend reading Attribute nightmare in IE (not for the faint-hearted).

Thanks Roger, that is something I will look out for. Thanks for the example as well, because, up until reading it I was thinking “this will never happen to me, I only give name attributes to inputs and I always give the same id”. Now I will never id anything “description” and I must look into other possibilities too!

Thanks for the tip of, Roger! I’m sure this will (or perhaps already has) come up at some time… I just can’t believe that a function that’s supposed to look only for ID’s somehow picks up name tags too. Silly IE.

Yes I went into the exact same issue, with the exact same id (description) some months ago and recognize your frustration ;) Almost like the classic in old versions of IE where you could misspell some properties without even getting an error, like spelling length as lenght and it still worked…

Even though IDs should be unique, I believe querySelectorAll() should (according to specs) return every element matched even if they have same IDs. So if IE messes it up I don’t believe “IDs should be unique” is a good reason not to return an array.

Unfortunately, my understanding of the spec indicates that despite the invalidity of multiple elements having the same id, we’re required to return all elements with a given id.

So, querySelectorAll(‘#foo’) will not be as fast as getElementById(‘foo’) because querySelectorAll should keep looking after it finds one.

Of course, instead of making it return an array it would be better to simply fix the bug. But then the best thing of all would be if some sort of virus destroyed every shred of IE out there and replaced it with a real browser.

@Rick: Because, like the spec states, the function “Returns the Element whose ID is given by elementId. If no such element exists, returns null. Behavior is not defined if more than one element has this ID.”
It clearly says ID and not name, that’s why IE is wrong.

@Mats: The DOM spec, which I think you are quoting, was written for XML Documents. Unfortunately for all, we live in HTML.

So let’s do an example. On some single element in an HTML doc, I set id=”slime” and name=”dorkus”. What should getElementByID(“dorkus”) return? The DOM says null, but HTML says a scripting engine should find the element.

And if I do getElementByID(“slime”), the DOM finds it and HTML implies I shouldn’t.

So which spec do you build your browser to support? I’m not saying IE’s getElementByID is correct. God strike me down first. I’m just confused.

I don’t see it as a real bug. The HTML 4.0.1 specification states that “the id attribute shares the same name space as the name attribute when used for anchor names.”

Hmm, that example in the spec is interesting. An h1 element whose id attribute has the same value as an a element’s name attribute causes a validation error, which is good since the attributes share the same name space. If the name attribute is on a meta or input element however, neither validating or checking with Tidy flags it as an error. So do they share the same name space only when the name attribute is on an a element? It isn’t exactly crystal clear, at least not to me.

I do agree that this is an edge case that you don’t run into very often and that you should avoid this situation, but if I can save a couple of people some frustration by revealing my stupidity it’s worth it ;-).

I ran into the same problem once, though with id=”keywords”. Especially when working on static templates that don’t have description or keywords meta tags all seems fine at first.

Btw, the script you link to in your post does not take Opera into account. And simply adding a UA string identifier to the if statement at the beginning is not enough to make it work.

I’ve tried to rewrite it for Opera and ended up adding a little extra: in this version the function rewrites itself depending on whether document.all is available (IE + Opera). That way the document.all check only has to be done once and for all browsers that don’t support that feature document.getElementById will just return to its original function.
I’ve tested the script on IE7, Fx2 and Op9.

I banged my head on that exact same problem just a couple days ago!
Terribly frustrating, I finally tracked it down firebug-like using the location bar: javascript:alert(document.getElementById('description').tagName);