Web Platform · HTML and Semantics
HTML Content Model Categories and What They Actually Constrain
Flow, phrasing, sectioning, embedded, interactive, and transparent content describe what may nest inside what. Browsers enforce a few of those rules by repairing the tree and ignore the rest.
A div inside a span is parsed into a div inside a span. It is also invalid HTML, because span accepts phrasing content and a div is not phrasing content. Both statements are true at once, and the gap between them is the whole subject of content models: they describe conformance, not parsing. An engine has no obligation to reject a document whose elements are nested against their content model, and mostly it does not try.
The categories exist because HTML has no schema language that could express the constraints declaratively. Instead the standard assigns each element one or more categories, and states each element’s content model as a combination of those categories plus prohibitions on specific descendants. The categories are the vocabulary in which every content model is written.
The eight categories
Metadata content covers elements that configure the document rather than render into it: base, link, meta, noscript, script, style, template, title. It is the category that governs what may appear in head.
Flow content is the large category of elements permitted in the body of a document: paragraphs, headings, lists, tables, forms, media, and generic containers. Almost every element that renders in normal flow is flow content, and body itself accepts flow content plus script and template.
Sectioning content is article, aside, nav, and section. These are the four elements that define the scope of header and footer. Notably, header, footer, main, and hgroup are not sectioning content even though their names suggest otherwise.
Heading content is h1 through h6 and hgroup.
Phrasing content is the category of inline-level text and inline elements: span, em, strong, code, a, img, input, label, br, and the rest. Phrasing content is what p, span, em, and most inline elements accept.
Embedded content covers elements that bring external resources into the document: img, iframe, video, audio, canvas, object, embed, svg, math. An embedded element is also flow content and usually phrasing content.
Interactive content covers elements designed to be operated by the user: a when it has an href, button, details, embed, iframe, label, select, textarea, input when its type is not hidden, img when it has a usemap attribute, plus audio and video when controls is present.
Palpable content is flow content that is not empty or hidden: text, embedded elements, form controls, and containers with at least one palpable descendant. It is used to express requirements that a region not be blank, and it is the reason a div holding only a hidden input is not palpable content even though both elements are flow content.
An element can belong to several categories at once. a with an href is flow, phrasing, interactive, and palpable content. img is flow, phrasing, and embedded. Membership is not exclusive, and the content models are written against whichever categories produce the constraint the author of the standard wanted.
Transparent models and the parent’s permission
a, ins, del, map, object, audio, video, canvas, and slot have a transparent content model. The model is not a category: it means the element’s own content must match whatever its parent accepts, with the element itself contributing no additional constraint. A link inside a paragraph may contain only phrasing content, because p accepts only phrasing content. The same link inside a div may contain flow content, because div accepts flow content.
Transparency is what makes block-level links legal in modern HTML: <a href="/x"><div>...</div></a> directly inside a flow container is conforming, while the same markup inside a p is not, because the div would be flow content in a position that admits only phrasing.
The transparent elements add prohibitions of their own. a must contain no interactive content and no descendant with a tabindex attribute, so an anchor wrapping a button is invalid even when the surrounding context would allow the button. audio and video must contain no media element descendants. canvas must contain no interactive content outside a short exception list that includes a, button, and input elements in the checkbox or radio state, which exist there as accessible fallbacks. Those prohibitions are about interactive descendants specifically, because the accessibility model treats a nested focusable as a user-interface trap.
Which violations the parser repairs
Most content model violations survive parsing intact. A div inside span stays there. A div inside ul stays there, even though ul accepts only li and script-supporting elements and the div has no list semantics at all.
A smaller set of violations coincide with parsing rules, because the tree builder closes or discards elements based on tags rather than on content models. Three patterns are worth recognizing.
<p>text<div>block</div></p> produces a paragraph, a div, and a second empty paragraph, because a block-level start tag closes an open paragraph. The author’s intention of one container is lost, and the result is valid markup with an extra element.
<table><div>text</div></table> moves the div before the table by foster parenting, leaving the table empty. The markup violated the table’s content model in a way that coincides with a parser rule, and the repair relocates rather than discards.
<select><div>text</div></select> drops the div’s tags entirely, because the in select insertion mode ignores start tags other than a short list of options and optgroups. The text is not dropped along with them: the character tokens are inserted, so the text becomes a bare text child of the select rather than the content of an option. That asymmetry between discarded tags and retained text is easy to miss.
Every one of these is described in How the Tokenizer and Tree Builder Recover from Malformed Markup. The point here is narrower: parsing behaviour is not evidence about conformance. A tree that looks reasonable is not proof that the source was valid.
Where the categories carry weight outside validation
Conformance checking is the obvious consumer. A validator holds the content model of every element and reports offending children, which is why a single unclosed paragraph can produce a cascade of errors further down the document.
ARIA mappings are a second consumer. li maps to a listitem role regardless of whether its parent is a list, so an orphaned item is exposed as a list item with no list around it. The element-to-role table in ARIA in HTML is written against the elements themselves rather than against their content models, so the mapping does not consult the surrounding structure; a tree that violates a content model can still produce a role mapping that looks reasonable.
Focus order is a third. Interactive content is expected to be focusable and operable; wrapping a button in an anchor creates two nested focusable regions whose activation semantics overlap. Browsers still render it, still focus both, and the user has to guess which activation wins.
A fourth consumer is the CSS author. A div inside a span becomes a block-level box inside an inline box, and the inline formatting context splits the span around the block. The visual result is usually not what the nesting suggests, because the box tree is constructed from display types rather than from the source nesting. That split is a rendering limitation, not an error, but it is triggered by exactly the markup the content model forbids.
Reading a content model precisely
Every element’s definition ends with a content model sentence built from the categories plus explicit exclusions. The exclusions carry most of the information. button accepts phrasing content but no interactive content and no descendant with tabindex. label accepts phrasing content with no descendant label elements and no labelable descendants other than the labelled control. table accepts a caption, then zero or more colgroup, then thead, then either tbody or tr, then tfoot in a fixed order. dl accepts groups of dt and dd, and the grouping constraint is expressible only in words.
script and template are script-supporting elements, and most content models admit them anywhere, which is why a script inside a ul is conforming and a div inside a ul is not. A content model that appears to forbid all non-list children usually permits script and template explicitly.
Reading those sentences against a real document is what a validator automates. The reason to understand the categories rather than to rely on the validator is that the validator runs after the markup exists. The categories answer the question earlier, when a component decides which element wraps its children, and when a template decides whether it can accept a block from its caller. A component that returns a div cannot be placed inside a paragraph, and parsing tolerance does not make the result valid.
The boundary with the next layer is the document outline, which the sectioning category was originally designed to drive. That plan did not survive contact with implementations, and its history is the subject of Sectioning Content and the Heading Outline Browsers Never Implemented.
References
- HTML Standard — Kinds of content — WHATWG
- ARIA in HTML — W3C
- Nu Html Checker — W3C