Firefox DOM - whitespace and newline
August 3rd, 2005In general I think Firefox’s handling of the Document Object Model (DOM) is excellent. The simple fact that they have DOM inspector puts them leagues ahead of anyone else.
But I recently came across something that I find surprising - not to mention pretty annoying.
Say I write the following XHTML:<div id="parent">
<div id="childOne"></div>
<div id="childTwo"></div>
</div>
If I have a look at this code in the DOM inspector, I see the following:

Looks good.
So now lets say I write a small bit of javascript. What I want to do is get the first <div>, childOne, then get it’s sibling. I might do this:child1 = document.getElementById("childOne");
nextChild = child1.nextSibling;
window.alert(nextChild.id);
Making use of nextSibling, I would expect this script to give an alert box with the text childTwo. In fact, in IE it does just that.
But in Firefox, you get undefined. Why?
Well I ran into this problem in a much more complicated application, so it took a long while to track down. But the answer is simple (and annoying).
Back to the DOM inspector. If I highlight the childOne <div>, then look at it’s javascript properties, I’ll see this:

There’s the problem. According to the Firefox DOM, this <div>s next sibling is “#text”. I would expect it to be the second <div>. So what’s going on?
Notice in my original XHTML I put the two child <div>s on separate lines. So there’s a linebreak in there. Turns out that Firefox is picking up that linebreak and treating it as a text node in the DOM. Unfortunately it doesn’t show up in the DOM inspector’s node map, but only in the Javascript properties.
So if I get rid of the line break like so:<div id="parent">
<div id="childOne"></div><div id="childTwo"></div>
</div>
Then go back to the DOM inspector I get this:

Now I’m getting the <div>s next sibling is “DIV”. That’s what I would expect. Notice in both of those images of the DOM inspector, the left pane is identical. There’s no indication that in the first instance there is actually a text node hidden between the <div>s.
So it appears that the Firefox DOM does not ignore line breaks. In fact, I tinkered around and it does not ignore whitespace at all. I find this surprising.
The W3C spec is a little non-committal on the subject. It says “This specification does not indicate the behavior, rendering or otherwise, of space characters other than those explicitly identified here as white space characters.” But in general browsers ignore whitespace. They give any amount of whitespace a single space when rendering. Thus the necessity for the <br /> tag and . This makes good sense. So it’s surprising to see Firefox give weight to whitespace and linebreaks.
So that’s the deal with that. But there’s still the practical problem of wanting to use nextSibling and not being able to. Again, IE works fine, so I needed a way to get Firefox up to speed. For my purposes, I chose to do the following:
- get the next sibling
- if this sibling is “#text” (or anything else other than an element), get the next sibling (so, the sibling’s sibling).
- repeat this until I hit a valid element
So I wrote the following javascript function:function getNextSibling(startBrother){
endBrother=startBrother.nextSibling;
while(endBrother.nodeType!=1){
endBrother = endBrother.nextSibling;
}
return endBrother;
}
So for the example I started with, instead of writingnextChild = child1.nextSibling;
I would now write nextChild=getNextSibling(child1);
This works in both IE and Firefox. A quick walk through that function: I’m basically getting the element’s nextSibling, then checking it’s node type. A node type of 1 indicates an element, which is what we care about. If the sibling we found isn’t of type 1, we get the next sibling, and check again. Repeat until we hit what we’re looking for. There are some potential problems here. First, if we never hit a valid element, this will go until it runs out of siblings, then will throw an error. Second, if the nextSibling is text, is going to the next sibling the right thing to do? It might not be.
I wrote a similar function for the firstChild function which I was also using.
The bottom line is that the Firefox DOM’s treatment of whitespace is really pretty annoying. I can’t say it goes against the spec per se, but I think a little more thought needs to go into this.
Excellent! Thank you, thank you thank you!
I have had this same problem, but couldn’t sort out the source of the problem.
This was it!
Well thanks to the folks at the web standards group, I’ve had some clarification on this.
By design, firefox considers whitespace to be DOM nodes. Mozilla has a document here
The idea is that the same DOM should apply to XML and XHTML. That is the whole idea behind XHTML right?
I gotta say though - whitespace is ignored by browsers in display (in fact you can’t make it relevant if you want to) so should it be relevant in the DOM?
I think having the whitespace is fine, and may be particularly useful in some unique cases. However, I think it should be *optional* in the parser (and turned off by default). I imagine that 99.9999% of the time, people use spaces, tabs and/or carriage-returns to make XML human-readable…while similarly 99.9999% of the time, nobody cares about them while parsing the XML in code.
Mike,
I’m with you on this in practice 100%.
In theory though, I’ve considered it further, and my comment above, “browsers ignore whitespace” is not accurate.
The PRE tag respects whitespace. In fact all tags are aware of whitespace, but every tag except PRE just styles it away.
So whitespace is not ignored by browsers, nor by the DOM.
But again, in practice… it’s a different story.
Hi guys,
I totally agree. If they really want to use the DOM parser for xml as well as for xhtml, it doesn’t make sense to incorparate breaklines. Since xml will almost always be formatted using breaklines and tabs to have some readability of the xml.
However the responsibility for this issue might lie with W3C first. If they would specify that whitespaces and breaklines should be standardly ignored and optionally turned on. I’m sure that the mozilla firefox team would incorparate this. As well as other W3C following developments (which should be all).
Cheers!
…Timmo
Thanks,
you saved my code, I didn’t understand why the nextsibling return Text Object and that works in IE.
Good Job
Merci
Also, white space is significant in text areas and text inputs.
Many thanks for the explanation! Hit the same problem myself, and kind of worked round it by trial and error. I always worry about using hacks, though, when I don’t know WHY they work. Now I can sleep easy…
Bingo! I hit exactly the same issue and your code came to my rescue. I can now put to bed a longstanding problem report.
Thanks.
Found your post from way back last year… but still relevant! Thanks.
How about checking endBrother before accessing it’s nodeType, to avoid JavaScript errors when running out of siblings:
while(endBrother && endBrother.nodeType!=1){ …
Yeah, I’m working on what I though would be a simple AJAX problem: pulling, essentially, a text file from the server, treating it as xml, and parsing it, but the resulting javascript DOM object seriously tripped me up for the last two days…. I don’t like it at all.
Nice function, this problem is annoying.
What’s really strange is that IE often renders stuff to the display to do with whitespace, but then ignores it in JavaScript. Mozilla usually ignores it when rendering but ’sees’ it when traversing the DOM in JavaScript. Argh!
Brillian!
Thanks for the solution. Luckily I stumbled across this after only a few minutes of debugging. Works perfectly.
Thanks for the info. I’m just starting to learn how to manipulate DOM with Javascript, and I was wondering why, when I made a “while” loop to list the childNodes of my div, it kept showing these random “text” elements there. I’m amazed to see Firefox being a problem as opposed to IE for once.
Thanks, saved me trouble!
This was great help. Thanks.
Had the problem in a web app i’m developing, tried to get to the root cause of it for a couple of days to no avail, 15 minutes after I found this post - problem solved.
Hi,I found your post very useful.
I have only modified your while condition from:
while(endBrother.nodeType!=1){
to
while(endBrother && (endBrother.nodeType!=startBrother.nodeType)){
in order to avoid errors if you reach the end of the document.
Thank you very much :)
Bye
Raffy
[...] Apparently W3C’s spec leaves it up to the UA to figure out what to do with whitespace, and Firefox is treating white-space as a text node in the DOM model (no, I didn’t figure out that part: this one guy looked at the DOM inspector for some javascript he was coding). Which confirms my theory that Firefox is turning my linebreaks into a space. I suppose there’re some technical reasons Firefox does this, but it’s really, really annoying. [...]
[...] The full article can be found on the Agave Group Design website. Filed under: Uncategorized | [...]
Actually, the implementation is correct, XML parsers must be aware of whitespace. If you have used XML parsers in other languages you have to specify if you want to ignore whitespace nodes. I’m doing some research to find if there is an option to ignore whitespace nodes in mozilla. Else I will have to code something to remove the whitespace nodes before processing my xml.
(belated comment) Thanks for the workaround. What a weird decision to implement the previousSibling, nextSibling. Thanks to Mozilla for making life more complicated than it really has to be.
[...] This post describes a weird difference in how Internet Explorer and Firefox handles the Document Object Model (DOM). In my case I got different browser-behaviour when using firstChild and nextSibling in a javascript. The problem is that the Firefox DOM does not ignore line breaks and whitespaces while IE does. [...]
IE and Firefox different approaches on several things are really torturous.
This article just saved my day, so thanks :)
Hey:)
Thanks!!!!!!
nextSibling function worked great for me. Just wondering about the firstChild version of the function, can you post it - i’m a bit confused:-(
Thanks for this. I was having the same problem. I needed the solution for firstChild, but managed to figure it out thanks to the function you provided above.
Wow, this works, thanks you!