skip to content

Content Models and When div/span Are Right

The spec defines which elements may nest inside which via content categories, and div/span exist precisely for the cases where no semantic element applies. Knowing that a div inside a p is invalid — and what the parser does about it — is a strong signal.

part ofHTMLoverview, primer and where to startread it →
on this pageshow

questions

5

In HTML, when is a <div> or a <span> the right element to use, and how do you choose between the two?

level: juniorimportance: must knowfreq 65%

answer

  1. the two elements with no meaning
  2. one wraps blocks, one wraps text
  3. content model, not the rendering box
  4. last resort after the real element
  5. both map to the generic ARIA role

basics

~20 s

Reach for div or span only when no element with meaning fits — they carry no semantics. div is a flow-content container for blocks of content; span is a phrasing-content container for a run of text inside a line.

solid answer

~40 s

`div` and `span` are the two deliberately meaningless elements in HTML: they exist so you can group or mark up content when nothing in the language describes what it is. The choice between them is a content-model choice, not a styling choice. `div` accepts flow content — paragraphs, lists, headings, other divs — so it wraps a chunk of the document. `span` accepts only phrasing content, so it wraps text and text-level elements inside a line, and putting a `<p>` or a `<div>` inside it is invalid. Both map to the ARIA `generic` role, which is the point: assistive technology gets nothing from them, so if the content really is a list, a paragraph, a heading or a button, that element is the correct answer and the wrapper is not.

code

html · 16 lines
html
<!-- generic: no meaning conveyed to anyone -->
<div class="heading">Recent orders</div>
<div class="list">
  <div class="item">Order 1201</div>
  <div class="item">Order 1202</div>
</div>

<!-- meaningful: heading + list are exposed to assistive technology -->
<h2>Recent orders</h2>
<ul>
  <li>Order 1201</li>
  <li>Order 1202</li>
</ul>

<!-- a legitimate span: marking a fragment of text -->
<p>Shipping to <span class="country">Portugal</span> takes 3 days.</p>

go deeper

for a junior

Be able to say plainly that div and span carry no meaning, that div wraps chunks and span wraps text inside a line, and that you reach for them only when no element describes the content.

for a middle

Explain the choice as a content-model rule — div takes flow content, span takes phrasing content — and show you know that rendering as block or inline does not change the category or where the element may legally appear.

for a senior

Show the production cost of generic wrappers: lost keyboard behaviour, lost landmarks and heading navigation, and rebuild work when a styled div has to become a real control. Be ready to argue where a wrapper is still the right call.

for a principal

Own the standard across a codebase: how component libraries make the semantic element the default and the wrapper the explicit opt-out, and how you keep that enforceable without turning markup review into taste debates.

## The two elements that mean nothing Almost every element in HTML tells a consumer something: `<p>` says paragraph, `<nav>` says navigation, `<button>` says activatable control. `div` and `span` are the two elements defined to say nothing at all. The specification describes `div` as an element with "no special meaning at all" and `span` likewise as a generic wrapper. That is not a defect — it is the escape hatch the language needs so authors are not forced to abuse a meaningful element for a grouping that has no meaning. Both are mapped to the ARIA `generic` role, so they add nothing to the accessibility tree. A screen-reader user gets no information from either. ## div vs span is a content-model decision The real difference is what each is allowed to contain, and where each is allowed to appear: - `div` has a content model of **flow content** — nearly anything that can live in the body: headings, paragraphs, lists, tables, other divs, and text. - `span` has a content model of **phrasing content** — the text-level subset: text nodes, `a`, `em`, `strong`, `code`, `img`, `br`, and other spans. Because phrasing content is itself a subset of flow content, a `span` can go anywhere a `div` can, but not the reverse. A `span` is valid inside a `<p>`; a `div` is not, because `p` only accepts phrasing content. ```html <!-- valid: span is phrasing content, so it belongs inside a paragraph --> <p>Total: <span class="amount">42</span> items</p> <!-- invalid: div is flow content and p only accepts phrasing content --> <p>Total: <div class="amount">42</div> items</p> ``` A common misreading is that this is about being "block" or "inline". Those are rendering concepts controlled by the stylesheet, and changing how an element renders does not change its category in the HTML content model. A `span` you render as a block is still phrasing content, and a `div` you render inline is still flow content and still invalid inside a `<p>`. ## When a wrapper is genuinely correct Legitimate uses of `div` and `span`: - A grouping that exists purely for layout or for a style hook, and that names nothing in the document's structure — a row, a column, a card shell around content that already carries its own semantics. - A hook for scripting or for a `data-*` attribute on a chunk of content that has no better home. - Marking a fragment of text so it can be styled or targeted — highlighting a substring, wrapping a currency symbol, isolating a word. Illegitimate uses — where a real element exists: - A clickable `div`, when `<button>` gives focusability, Enter/Space activation and a button role for free. - A `div` per row of a bulleted list, when `<ul>`/`<li>` conveys the list and its item count. - A `div` with large text acting as a title, when `<h2>` puts the title in the document's heading structure. - A `span` used for emphasis, when `<em>` or `<strong>` conveys it. The rule of thumb interviewers want to hear: **choose the element that describes the content; fall back to `div`/`span` only when no element does.** The generic element is a last resort, not a default. ## Why "div soup" is a real cost, not a style opinion When semantics are replaced by generic wrappers, three things quietly disappear. First, behaviour: a real control comes with keyboard activation and form participation you would otherwise have to rebuild. Second, structure: assistive technology navigates by headings, landmarks and lists, and a page of divs offers no landmarks to jump to. Third, resilience: consumers other than your own stylesheet — reader modes, translation tools, search crawlers, future maintainers — read the element names, not the class names. None of that says wrappers are bad. A page will legitimately contain many divs. It says a `div` should be the answer to "there is no element for this", and never the answer to "I did not check whether there is one". ## Practical check Before writing a wrapper, ask what you would call the thing out loud. If the answer is a word HTML already knows — list, paragraph, heading, navigation, button, table, quote, form field — use that element. If the honest answer is "a box" or "a bit of text", `div` and `span` are exactly right, and using them is not a compromise.

  • Does giving a span a block rendering in the stylesheet change where it may legally appear in the markup?
    No. The content model is a specification category fixed by the element, not by how it is rendered. A `span` stays phrasing content however it is displayed, and a `div` stays flow content — so a `div` rendered inline is still invalid inside a `<p>`, and a `span` rendered as a block is still valid there.
  • If div and span add nothing to the accessibility tree, why does adding lots of them still matter to a screen-reader user?
    Because of what they replace. Assistive technology navigates by structure — headings, landmarks, lists, controls. Every heading rendered as a styled `div` is one fewer jump target; every list of divs loses the item count; every clickable `div` loses keyboard activation. The wrappers themselves are inert, but they crowd out the elements that were not.
  • Is it ever right to wrap content that already has a semantic element in an extra div?
    Yes. If you need a grouping purely for layout or as a script or `data-*` hook, and that grouping names nothing in the document, a `div` around an existing `<article>` or `<ul>` is correct — you are adding a box, not replacing meaning. The defect is substituting a `div` for the semantic element, not surrounding it.

div and span are the plain cardboard boxes of HTML: perfect when nothing on the shelf fits, wasteful when the labelled box was right there.

saying these in an interview costs you the question

  • div is for block content, span is for inline content
  • Adding role and tabindex makes a div as good as a button
  • Using div everywhere is fine because CSS handles the look
  • span is just a div that does not break the line
  • Semantic elements are only about SEO

context

open as a page

Why is the markup `<p>Intro <div>Block</div></p>` invalid HTML, and what DOM does the browser actually build from it?

level: middleimportance: should knowfreq 50%

basics

~20 s

The p element accepts only phrasing content, and div is flow content, so the nesting is invalid. The parser closes the open p when it sees the div start tag, so the div becomes a sibling of the paragraph — and the trailing </p> produces a second, empty paragraph.

open as a page

In HTML's content model, what is the difference between flow content and phrasing content, and how does that distinction decide what may nest inside an element?

level: middleimportance: should knowfreq 45%

basics

~20 s

Flow content is nearly everything allowed in the body; phrasing content is its text-level subset — span, em, a, img, input. Each element's specification content model names the category it accepts, and that is what makes some nestings valid and others invalid.

open as a page

A card component wraps its entire markup in an <a href> and that markup contains a <button>. Why does HTML's content model forbid this, and what would you do instead?

level: seniorimportance: should knowfreq 40%

basics

~20 s

The a element's content model forbids interactive content descendants, and button is interactive content, so nesting a control inside a link is invalid. Restructure the markup: link only the non-interactive content, and place the button as a sibling outside the anchor.

open as a page

The HTML specification gives the <a> element a transparent content model. What does transparent mean, and what may an <a> therefore wrap?

level: middleimportance: nice to knowfreq 28%

basics

~20 s

A transparent content model means the element accepts whatever its own parent accepts. So an <a> inside a div may wrap flow content such as a whole article, while the same <a> inside a p may wrap only phrasing content.

open as a page