Skip to Main Content
×
Freshbooks
Official App
Free – Google Play
Get it
FreshBooks is Loved by American Small Business Owners
FreshBooks is Loved by Canadian Small Business Owners
FreshBooks is Loved by Small Business Owners in the UK
Dev Blog

The Importance of Strict HTML

by Taavi on March 3/2008

The other day I was investigating an odd error using our development version of FreshBooks in Safari. Lines in an invoice were being reset in an odd way, and I couldn’t add more lines to an invoice as I was creating it. This worked perfectly in FireFox, but not in Safari.

Of course, the first step was to look at the page source. However, the page source looked entirely correct. All of the form elements were defined in the correct places, with the expected order. This is where fantastic tools like Web Inspector (found in the Safari Debug menu) and Firebug come in handy. On reproducing the bug, I managed to SEE the offending tag in its new location in the Web Inspector view. A whole set of input tags sitting at the start of a table!

It turns out that if you replace a table inside a div tag, Safari does some reparsing of your provided HTML. Say, you put a hidden input tag within a tr, but outside of a td. Normally this works fine, and document.forms[0].elements[] shows up in the way you’d expect. But when replacing the table via something like innerHTML, it barfs because the ONLY things allowed in a tr tag are th or td. Thus speaks the XHTML 1.0 transitional DTD:

<!ELEMENT tr (th|td)+>

What appears to happen, is that any input elements outside of a td get bubbled up the DOM until they find a place where they are allowed…in this case, immediately before the enclosing table.

Hence, you get strange results with:

myDiv.innerHTML = "<table border='1'><tbody>" +
"<tr><td><input type='text' value='First'></td>" +
" <input type='text' value='Second'></tr>" +
"</tbody></table>";

But not with:

myDiv.innerHTML = "<table border='1'><tbody>" +
"<tr><td><input type='text' value='First'>" +
" <input type='text' value='Second'></td></tr>" +
"</tbody></table>";

Hence, when adding form elements improperly, programmatically, and referencing them with document.forms[].elements[], you get Very Strange results.

So please, for your own sanity’s sake, nest your elements properly!