Dorward's Ramblings

Document type does not allow element here

Published on

A common, but fairly confusing error produced by the W3C Markup Validatation Service is: document type does not allow element "foo" here.

This, in itself, is fairly clear. A link may not contain a heading, a paragraph may not contain a table, but is complicated by many users not understanding what elements are allowed where, and by the rest of the error message which reads something like: missing on of "p", "h1", "h2", "h3", "h4", "h5", "h6", "div", "pre", "address", "fieldset", "ins", "del" start-tag.

This is a list of elements which (according to the DTD) may contain the element "foo" and may be contained by the element that the document attempts to contain "foo" with.

There are three common causes of this error:

The form and body element only accept block level children

<form action="/">
  <input type="submit">
</form>

… will produce the error:

document type does not allow element "input" here; missing one of "p", "h1", "h2", "h3", "h4", "h5", "h6", "div", "pre", "address", "fieldset", "ins", "del" start-tag.

In Strict variants of (X)HTML, a form element may have only block elements as its children, but form controls (such as input elements) are inline elements. The solution is to pick a block element with appropriate semantics that may contain inline elements; helpfully the validator produces a list that can help you narrow it down.

When it comes to a form, appropriate elements are usually fieldset or a plain div.

Paragraphs and inline elements containing blocks

Paragraphs

<p>
  <table><tr><td>x</td></tr></table>
</p>

This is a highly contrived example, so please don't treat this as a good use of a table element!

Here we get the error message:

document type does not allow element "table" here; missing one of "object", "ins", "del", "map", "button" start-tag.

This is a bit of a sticky situation. The solution to the problem is to remove the paragraph element entirely, but the error message suggests you can add an element around the table and everything will be OK.

This is because the listed elements can be both block level or inline depending upon the context in which they are used. If we look at the prose of the HTML specification we see:

The INS and DEL elements must not contain block-level content when these elements behave as inline elements.

Although I'm not aware of a similar, explicit, prohibition on using the other elements in a similar way, it is sensible to act as though one exists.

Inline elements

A very similar case to the above is trying to contain a block element (such as a paragraph or a heading) inside an inline element (such as an a element (to create a link) or a font element.

This generally falls into one of two groups:

To paraphrase Fitt's law, Big things are easier to hit. Wrapping a heading or list item (or etc.) in a link will (depending on the error recovery of the browser) make a larger click target then linking the text alone.

You can achieve a similar effect by styling the link to display as a block. For lots of examples of this see listamatic.

Presentation

Some people, although its less common these days, try to wrap font elements around large sections of a document. Try CSS instead.

Wrapping a block around table rows

Sometimes authors wish to wrap a table row in a block element.

Divs

It is sometimes useful to wrap table rows in a block element to group collections of rows for styling or scripting purposes. Tables have elements specifically for this purpose - row groups.

Forms

It would be nice if a row of a table could be encapsulated within a form, it would making editing a representation of a database very easy, but HTML doesn't provide for this in that fashion.

You could achieve a similar effect by wrapping the entire table in a form and making use of a button element (which can act as a submit button with a value other then its display label) to identify which row of inputs should be acted upon. Such a pity that Microsoft Internet Explorer is too buggy for this to work.

The general solution is to submit every bit of data and look through it on the server for changes - which is unfortunate, but something we are rather suck with.