Skip to content

Text Semantics and Content Model

beginner14 min read

The Difference That Gets You Hired

In a frontend interview, you're asked to build a pricing card. Candidate A writes:

<div class="title">Pro Plan</div>
<div class="price">$29/mo</div>
<div class="features">
  <div>Unlimited projects</div>
  <div>Priority support</div>
</div>

Candidate B writes:

<article>
  <h3>Pro Plan</h3>
  <p><strong>$29</strong>/mo</p>
  <ul>
    <li>Unlimited projects</li>
    <li>Priority support</li>
  </ul>
</article>

Both look identical on screen. But Candidate B's version works with screen readers, gets indexed by search engines, and communicates meaning to any machine or human reading the source. Candidate A's is a pile of meaningless boxes.

Semantic HTML isn't about being pedantic. It's about writing markup that means something.

Mental Model

Think of HTML semantics like formatting a legal document vs. scribbling on a napkin. The napkin might have the same words, but a legal document has numbered sections, defined terms, clear hierarchies, and signatures — structure that gives the content its force. Semantic HTML gives your content its force on the web. Search engines, screen readers, browser reader modes, and AI tools all rely on that structure to understand what your page actually says.

Headings: Your Document's Outline

Headings create a hierarchical outline of your content. There are six levels, h1 through h6:

<h1>Frontend Engineering</h1>
  <h2>HTML Foundations</h2>
    <h3>Text Semantics</h3>
    <h3>Document Structure</h3>
  <h2>CSS Foundations</h2>
    <h3>The Box Model</h3>

The rules:

  • One h1 per page — it's the page's main topic. Think of it as the book title.
  • Don't skip levels — go h1 → h2 → h3. Never jump from h1 to h3 (screen readers announce the heading level, and a skip signals missing content).
  • Headings are for hierarchy, not sizing — if you want bigger text, use CSS. Never pick an h3 because it "looks the right size."

Screen readers let users navigate by headings. If your heading hierarchy is broken, it's like a book where chapter 3 comes after chapter 1.

Quiz
Why should you never skip heading levels (like going from h1 to h3)?

Text-Level Semantics

Emphasis vs. Decoration

This is where most developers get confused:

<!-- Semantic emphasis — screen readers stress this word -->
<p>You must <em>never</em> push to main without tests.</p>

<!-- Stronger emphasis / importance -->
<p><strong>Warning:</strong> This action cannot be undone.</p>

<!-- Visual-only bold/italic — no semantic meaning -->
<p>The movie <i>Inception</i> was released in 2010.</p>
<p>The keyword <b>class</b> is reserved in JavaScript.</p>
  • em — stress emphasis. The meaning of the sentence changes depending on which word is emphasized.
  • strong — strong importance. "This part really matters."
  • i — text in an alternate voice. Titles of works, technical terms, foreign words.
  • b — draw attention without added importance. Keywords, product names.

The difference matters for accessibility. Screen readers change their intonation for em and strong. They don't change anything for i and b.

Quiz
What is the difference between em and i elements?

Other Important Text Elements

<!-- Abbreviation with expansion -->
<p>The <abbr title="World Wide Web Consortium">W3C</abbr> maintains web standards.</p>

<!-- Inline code -->
<p>Use <code>document.querySelector()</code> to select elements.</p>

<!-- Marked/highlighted text -->
<p>Search results: the word <mark>closure</mark> was found 3 times.</p>

<!-- Time (machine-readable) -->
<p>Published on <time datetime="2024-01-15">January 15, 2024</time>.</p>

<!-- Small print (side comments, legal text) -->
<p><small>Terms and conditions apply.</small></p>

<!-- Deleted and inserted text -->
<p>Price: <del>$49</del> <ins>$29</ins></p>

Each of these carries meaning that plain text doesn't. A time element with a datetime attribute lets search engines and calendar apps parse the date. An abbr with a title shows the full form on hover.

Lists: Ordered, Unordered, and Description

<!-- Unordered list — items have no specific sequence -->
<ul>
  <li>HTML</li>
  <li>CSS</li>
  <li>JavaScript</li>
</ul>

<!-- Ordered list — sequence matters -->
<ol>
  <li>Open the terminal</li>
  <li>Run npm install</li>
  <li>Start the dev server</li>
</ol>

<!-- Description list — key-value pairs -->
<dl>
  <dt>HTML</dt>
  <dd>A markup language for structuring web content.</dd>
  <dt>CSS</dt>
  <dd>A stylesheet language for visual presentation.</dd>
</dl>

Lists aren't just bullets and numbers. Screen readers announce "list, 3 items" when they encounter a ul, helping users understand the structure. Navigation menus are typically ul elements because they're lists of links.

Lists can be nested:

<ul>
  <li>Frontend
    <ul>
      <li>HTML</li>
      <li>CSS</li>
      <li>JavaScript</li>
    </ul>
  </li>
  <li>Backend
    <ul>
      <li>Node.js</li>
      <li>Python</li>
    </ul>
  </li>
</ul>
Quiz
When should you use a description list (dl) instead of an unordered list (ul)?

The Content Model: What Goes Where

HTML elements are categorized by their content model — rules about what they can contain and where they can appear.

The main categories:

CategoryDescriptionExamples
FlowMost elements — the general categorydiv, p, ul, h1-h6, article
PhrasingInline-level contentspan, a, strong, em, code, img
SectioningDefine document sectionsarticle, section, nav, aside
HeadingSection headingsh1, h2, h3, h4, h5, h6
InteractiveUser-interactive elementsa, button, input, select, textarea
EmbeddedExternal contentimg, video, audio, iframe, canvas

The key rules:

  1. Phrasing elements can only contain other phrasing elements — a span can hold a strong, but not a div.
  2. Some elements have specific content modelsul can only contain li children. table has strict child requirements.
  3. Interactive elements cannot nest — you can't put a button inside an a, or an a inside a button.
<!-- Invalid: interactive inside interactive -->
<a href="/page">
  <button>Click me</button>
</a>

<!-- Valid: use one or the other -->
<a href="/page">Click me</a>
<!-- or -->
<button onclick="navigate('/page')">Click me</button>
Quiz
Why can you not nest a button element inside an a element?

Production Scenario: Screen Reader Navigation

A screen reader user visits your page. Here's what they hear depending on your markup:

Bad markup (div soup):

<div class="heading">Features</div>
<div class="list">
  <div>Fast</div>
  <div>Reliable</div>
</div>

Screen reader announces: "Features. Fast. Reliable." — no structure, no navigation landmarks, no way to skip around.

Good markup (semantic):

<h2>Features</h2>
<ul>
  <li>Fast</li>
  <li>Reliable</li>
</ul>

Screen reader announces: "Heading level 2, Features. List, 2 items. Fast, 1 of 2. Reliable, 2 of 2." — the user knows exactly what they're dealing with and can skip the list if they want.

Execution Trace
Parse heading
Browser creates h2 node in DOM
Accessibility tree marks it as a heading with level 2
Parse ul
Browser creates ul node with role 'list'
Screen reader can announce 'list, N items'
Parse li items
Each li gets role 'listitem'
Screen reader announces item position: '1 of 2', '2 of 2'
User navigates
User presses H key to jump to next heading
Only works because we used real heading elements, not styled divs
What developers doWhat they should do
Using h1-h6 to control text size instead of representing hierarchy
Screen readers navigate by heading levels. Using h3 because it 'looks right' breaks the document outline
Use headings for document structure, CSS for sizing
Using br tags to create spacing between elements
br is for line breaks in content, not for layout. A screen reader reads br as... nothing. CSS handles spacing
Use CSS margin or padding for spacing, br only for line breaks within text (like addresses or poems)
Wrapping everything in div and span elements
div and span carry zero semantic meaning. They should be your last resort, not your first choice
Choose the most specific semantic element: article, section, nav, ul, p, time, code
Nesting interactive elements like a button inside an anchor
The spec forbids interactive content inside interactive content. The click behavior is ambiguous and assistive tech can't resolve it
Use one interactive element — either a link or a button, not both

Challenge: Rewrite Div Soup as Semantic HTML

Convert this markup to use proper semantic elements:

<div class="post">
  <div class="post-title">Understanding Closures</div>
  <div class="post-date">January 15, 2024</div>
  <div class="post-body">
    <div class="intro">Closures are one of JavaScript's most powerful features.</div>
    <div class="section-title">What Is a Closure?</div>
    <div class="text">A closure is a function that remembers its outer scope.</div>
    <div class="key-points">
      <div>Functions carry their scope</div>
      <div>Variables stay alive through references</div>
      <div>Memory cost depends on what's captured</div>
    </div>
  </div>
</div>
Show Answer
<article>
  <h2>Understanding Closures</h2>
  <p><time datetime="2024-01-15">January 15, 2024</time></p>
  <p>Closures are one of JavaScript's most powerful features.</p>
  <h3>What Is a Closure?</h3>
  <p>A closure is a function that remembers its outer scope.</p>
  <ul>
    <li>Functions carry their scope</li>
    <li>Variables stay alive through references</li>
    <li>Memory cost depends on what's captured</li>
  </ul>
</article>

Changes made:

  • Outer div.postarticle (self-contained content)
  • div.post-titleh2 (heading)
  • div.post-datetime inside p (machine-readable date)
  • div.intro and div.textp (paragraphs)
  • div.section-titleh3 (subheading under h2)
  • div.key-points with child divs → ul with li items (unordered list)
  • Every element now carries semantic meaning for search engines, screen readers, and browser reader modes.
Key Rules
  1. 1Use headings for document hierarchy (one h1 per page, never skip levels) — never for visual sizing
  2. 2em means stress emphasis (changes sentence meaning), strong means importance — i and b are for alternate voice and attention without emphasis
  3. 3Choose the most specific semantic element available before falling back to div or span
  4. 4Interactive elements cannot nest inside other interactive elements — pick one and stick with it
  5. 5Content model rules determine what can nest where — phrasing elements cannot contain flow elements