Much of this comes about because HTML5 merges the successor to HTML 4 and XHTML 1.x into a single specification.
When XHTML 1.0 was introduced and browsers started to experiment with using an XML parser, they hit a problem. Authors were used to writing <table>
s without <tbody>
s. Since an XML parser isn't allowed to infer tags like HTML parsers did, the best way to help authors to transition to XHTML (which seemed like a good idea at the time) was to get the tables to render properly by allowing <tr>
s to be the direct children of <table>
inside the DOM. (The DOM is as much as possible the same, regardless of whether it originated from an HTML parse or an XML parse.) So the browsers implemented support for this.
Now the HTML5 content model is shared between the HTML and XHTML serializations of HTML5, so it has to allow for both arrangements, i.e. with or without tbody.
On the other hand, in the section on "The HTML Syntax" (which does not apply to the XML parser), it makes clear that an HTML parse will infer the tbody tags.
When <table><tr><td>my text</td></tr></table>
is served as text/html
the table structure created in the DOM will have the tr as a direct child of a tbody which is the direct child of the table. The HTML5 content model says this is OK.
When <table><tr><td>my text</td></tr></table>
is served as application/xhtml+xml
the table structure created in the DOM will have the tr as a direct child of the table. The HTML5 content model says this is also OK.
It is also possible to create a tr as a direct child of table through scripting. For the same reason, browsers will treat this as a table row as most people expect it to.