Python · SQL · Web Dev · Java · AI/ML tracks launching soon — your one platform for all of IT
Beginner+150 XP

Text Elements & Semantic Structure

Headings, paragraphs, and the semantic tags — header, nav, main, section, article, aside, footer — that give a page real meaning.

40 min August 2026
// Part 01 — The Heading Hierarchy

h1 Through h6 — A Hierarchy, Not a Font-Size Picker

HTML gives you six heading levels, <h1> through <h6>, ranked from most to least important. Browsers apply default styling that makes <h1> the largest and boldest and <h6> the smallest — but treating headings as a font-size shortcut is exactly the mistake this section exists to correct. Their real job is expressing the logical outline of a document, the way chapter titles and subheadings work in a book's table of contents.

A correctly nested heading hierarchy
<h1>Trailhead Boots</h1>

<h2>Waterproof Hiking Collection</h2>
  <h3>Men's Styles</h3>
  <h3>Women's Styles</h3>

<h2>Trail Running Collection</h2>
  <h3>Lightweight Models</h3>
  <h3>All-Terrain Models</h3>

Read purely as structure, with all styling stripped away, this tells you exactly how the page is organized: one top-level topic, two major sections beneath it, and two subsections under each. A screen-reader user can navigate a page exactly this way — jumping heading to heading, skipping straight to "Women's Styles" without reading everything in between — which is precisely why this hierarchy is not a cosmetic detail.

Never skip a level

The hierarchy should descend one level at a time. Jumping from <h2> straight to <h4> because the smaller heading's default font size "looked right" is a genuinely common mistake, and it breaks the logical outline even though the page still renders without any visible problem.

Wrong — skips h3 entirely, purely because h4's default size looked better
<h2>Trail Running Collection</h2>
<h4>Lightweight Models</h4>   <!-- should be h3 -->
⚠️ Important
Never choose a heading level for its default font size. If <h3> renders bigger than you want, that is a CSS problem — override itsfont-size in your stylesheet (covered in the CSS Foundations phase). Do not solve a visual problem by breaking the document's logical structure; the two are entirely separate concerns, and conflating them is exactly the div-soup-adjacent mistake this whole module is steering you away from.

One h1 per page — the convention, and its real nuance

The long-standing convention is exactly one <h1> per page, representing that page's single main topic — the same way a book chapter has one title, not several competing for the top spot. Since HTML5, the specification technically permits multiple <h1> elements when each is scoped inside its own <article> or <section> (each effectively starting a fresh sub-outline) — but in practice, essentially every accessibility guideline, SEO best-practice document, and real production codebase you will encounter still treats a single page-level <h1> as the expected, unambiguous norm. Deviating from it is a decision worth being deliberate about, not a default.

// Part 02 — p vs div

<p> vs <div> — Text Content vs a Generic Container

<p> marks up a paragraph — a block of actual, readable prose. <div> is a generic, meaning-free container that exists purely to group other elements for styling or scripting purposes. Confusing the two — most often, wrapping running text in a <div> instead of a <p> — is one of the most common structural mistakes in beginner HTML.

p for actual text content; div for structural/visual grouping
<div class="product-card">
  <h3>Trail Runner GTX</h3>
  <p>A lightweight trail shoe with a Gore-Tex membrane for wet-weather
  traction on technical terrain.</p>
  <p>Available in three colorways, starting at $139.</p>
</div>

<!-- div groups the whole card for styling — it carries no meaning of
     its own. Each block of actual prose is a <p>, not another <div>. -->

The practical difference is not just philosophical. Screen readers announce <p> elements as paragraphs and let users jump between them; browsers apply sensible default spacing (margin) around paragraphs that a plain <div> does not get; and search engines weight text inside meaningful content tags differently than text inside a generic container with no semantic role at all.

🎯 Pro Tip
A quick test: if you are writing a sentence or a block of prose someone would actually read top-to-bottom, it almost certainly belongs in a <p>. If you are grouping other elements together purely to apply a shared style or layout to them as a unit, <div> is the correct, honest choice — using it does not mean you did something wrong, it means you correctly identified that the group itself carries no specific meaning beyond "these belong together visually."
// Part 03 — Div Soup

"Div Soup" — What It Actually Looks Like, and Why It's a Problem

"Div soup" is the industry nickname for a page built almost entirely out of generic <div> elements, with classes doing all the work of describing what everything is — class="header", class="nav", class="main-content" — instead of using the HTML elements that already exist specifically to express those roles.

Div soup — visually correct, structurally meaningless
<div class="header">
  <div class="logo">Trailhead Boots</div>
  <div class="nav">
    <div class="nav-item">Shop</div>
    <div class="nav-item">About</div>
  </div>
</div>
<div class="main-content">
  <div class="article">
    <div class="article-title">New Arrivals</div>
    <div class="article-body">...</div>
  </div>
</div>
<div class="footer">© 2026 Trailhead Boots</div>

Styled with the right CSS, this can look absolutely identical to a well-structured page — the problem is entirely invisible to a sighted user clicking through it casually. It becomes very visible to anyone, or anything, not relying on vision or CSS to understand the page: a screen reader has no landmarks to announce or jump between, a search engine has no signal for which block is the real navigation versus the real content, and a browser's reader mode has nothing reliable to extract. Part 05 covers the specific elements that fix this exact pattern.

⚠️ Important
Div soup is not a beginner-only mistake — it shows up constantly in real production codebases, usually because a component was built quickly under deadline pressure with styling as the only concern, and semantic correctness was never revisited afterward. Recognizing it in someone else's code (or your own, from six months ago) is a genuinely common and valuable code review skill.
// Part 04 — The Document Outline

The Document Outline — What a Machine Understands About Your Page's Shape

The document outline is the logical, tree-shaped summary of a page's content that headings and semantic elements together produce — conceptually similar to a table of contents generated automatically from the structure itself, without anyone writing it by hand. It is what a screen reader's "jump to heading" navigation is built from, what browser reading-mode extraction relies on, and what search engines use to understand which part of a page is the actual article versus surrounding chrome like navigation and footer content.

Markup and the outline it implies
<header>...</header>
<nav>...</nav>
<main>
  <h1>Trail Running Shoes</h1>
  <section>
    <h2>Men's Collection</h2>
    <article>
      <h3>Trail Runner GTX</h3>
    </article>
  </section>
  <section>
    <h2>Women's Collection</h2>
  </section>
</main>
<footer>...</footer>

/* Implied outline:
   Trail Running Shoes
     └── Men's Collection
           └── Trail Runner GTX
     └── Women's Collection      */

This is precisely why heading levels and semantic elements matter together rather than separately — a correct heading hierarchy inside a page built entirely from unlabeled <div>s still leaves assistive tools unable to tell where the actual main content starts, and correct semantic landmarks with a broken or skipped heading order still leave the internal structure of the content unclear. Both are needed for the outline to actually mean something.

// Part 05 — Semantic Landmark Elements

header, nav, main, footer — The Elements That Fix Div Soup

HTML5 introduced a set of elements specifically to replace the class="header"-style pattern with real, machine-recognizable structure. These are called landmark elements, because assistive technology treats them as navigable landmarks a user can jump directly to.

The core landmarks, used correctly
<body>
  <header>
    <h1>Trailhead Boots</h1>
    <nav>
      <ul>
        <li><a href="/shop">Shop</a></li>
        <li><a href="/about">About</a></li>
      </ul>
    </nav>
  </header>

  <main>
    <!-- the ONE primary content area of the page -->
    <h2>New Arrivals</h2>
    ...
  </main>

  <footer>
    <p>&copy; 2026 Trailhead Boots</p>
  </footer>
</body>

A few rules worth being precise about: <main> should appear exactly once per page, wrapping the primary content unique to that specific page — not the navigation, not the footer, not anything repeated across every page of the site. <header> and <footer> can each appear more than once, since they can also be scoped to an individual <article> or <section> (a blog post's own byline-and-date header, for example), not only at the page level. <nav> should wrap a genuine navigation block — a primary menu, a breadcrumb trail, a pagination control — not every single group of links on the page; a handful of related links inside an article's body does not need to be wrapped in <nav>.

🎯 Pro Tip
A fast way to check whether landmarks are being used correctly on a real, live page: open DevTools' Accessibility tree (or Firefox's dedicated Accessibility panel) and look at the landmark regions it reports. If it reports a sensible list — banner (header), navigation, main, contentinfo (footer) — the semantics are doing their job. If it reports nothing but generic groups, that page is very likely built from div soup.
// Part 06 — section, article, aside

section vs article vs aside — And When a Plain div Is Still Correct

These three elements are the ones beginners mix up most often, because they can look nearly interchangeable in a quick glance at rendered output. Each has a specific, distinct meaning.

The distinction, defined precisely
<article>  →  Content that would make complete sense on its own, removed
              from the page entirely — a blog post, a news story, a single
              product listing, a forum comment. Ask: "could this be
              syndicated/republished elsewhere and still make full sense?"

<section>  →  A thematic grouping of content, WITH ITS OWN HEADING, that is
              part of a larger whole — a chapter-like grouping. Ask: "does
              this have its own heading, and is it one distinct part of a
              bigger document?"

<aside>    →  Content related to, but not essential to, the main content
              around it — a sidebar, a pull quote, a "related articles"
              box. Ask: "could a reader skip this entirely without losing
              the main point?"
All three used correctly together on one page
<main>
  <article>
    <h2>Why Waterproofing Ratings Matter</h2>
    <p>A 20,000mm rating means...</p>

    <section>
      <h3>How Ratings Are Measured</h3>
      <p>...</p>
    </section>

    <section>
      <h3>Comparing Common Ratings</h3>
      <p>...</p>
    </section>
  </article>

  <aside>
    <h3>Related Reading</h3>
    <ul>
      <li><a href="/blog/gore-tex-explained">Gore-Tex, Explained</a></li>
    </ul>
  </aside>
</main>

The section rule people miss most: it needs its own heading

A very common mistake is reaching for <section> purely as "a bigger div," without giving it a heading of its own. If a grouping of content has no heading identifying it as its own distinct thematic unit, it is not a <section> — it is very likely just a <div>, and that is the correct, honest choice in that situation.

Wrong — a section with no heading of its own
<section class="card-grid">
  <div class="card">...</div>
  <div class="card">...</div>
</section>
<!-- No heading identifies this as its own thematic unit — plain div
     is the honest choice here, not section. -->
⚠️ Important
<div> is not a mistake to eliminate everywhere. Not every grouping of content is a meaningful semantic unit — a purely visual wrapper used to apply a CSS Grid layout to a set of cards, with no shared heading or thematic identity of its own, is exactly what <div> is for. Reaching for <section> everywhere "to be more semantic" without a heading inside each one is its own kind of mistake — it adds structure the document outline does not actually have.
// Part 07 — Real World
💼 What This Looks Like at Work

An Accessibility Audit Fails a Chicago News Site's Homepage

Scenario — Local news publisher, Chicago · Accessibility audit

A Chicago-based local news site commissions a third-party accessibility audit ahead of a legal compliance deadline. The homepage looks completely normal — a masthead, a navigation bar, a grid of story cards, a footer — and passes every visual review the internal team ran. The audit comes back with a failing score anyway, flagged specifically for "no identifiable landmark regions" and "heading structure does not reflect page content."

What the audit tool actually found

The page was built entirely from <div> elements with CSS classes doing all the labeling — class="header", class="nav", class="story-headline" — with the actual headline text inside <div> tags styled to look exactly like headings, rather than real <h2> or <h3> elements. Sighted users scanning the page visually never noticed a problem, since the CSS made everything look correct. A screen reader, which relies entirely on real elements rather than class names, announced the entire homepage as one undifferentiated block of unlabeled text with zero navigable landmarks or headings.

What was actually shipped
<div class="header">
  <div class="masthead">Chicago Daily</div>
  <div class="nav">
    <div class="nav-link">Local</div>
    <div class="nav-link">Politics</div>
  </div>
</div>
<div class="story-card">
  <div class="story-headline">City Council Approves Budget</div>
  <div class="story-summary">...</div>
</div>
The remediation the audit required
<header>
  <h1>Chicago Daily</h1>
  <nav>
    <ul>
      <li><a href="/local">Local</a></li>
      <li><a href="/politics">Politics</a></li>
    </ul>
  </nav>
</header>
<main>
  <article class="story-card">
    <h2>City Council Approves Budget</h2>
    <p class="story-summary">...</p>
  </article>
</main>

The visual design did not change at all — the CSS classes stayed exactly the same, still controlling every pixel of appearance. Only the underlying elements changed, from generic <div>s to the correct semantic and heading elements each block actually represented. The remediation passed re-audit, and — a detail the team had not anticipated — organic search rankings for individual story pages measurably improved in the following weeks, since search engines now had real heading and article structure to index instead of an undifferentiated wall of divs.

// Part 08 — Misconceptions

Five Misconceptions About Semantic Structure

✕ ""Heading levels are just about font size — pick whichever one looks right""
Heading levels express the logical outline of the page, consumed directly by screen readers and search engines. If a heading's default size is wrong for your design, override it with CSS — never pick a heading level purely to get a certain size.
✕ ""section is just a more modern name for div""
section specifically means a thematic grouping WITH its own heading, as one part of a larger document. A grouping with no heading of its own — a purely visual wrapper for a CSS layout, for instance — is correctly a div, not a section.
✕ ""If it looks correct visually, the semantics don't really matter""
CSS can make a div-soup page look pixel-identical to a properly structured one. The difference is entirely invisible to sighted users clicking through casually, and entirely visible to screen readers, search engines, and any tool that reads structure rather than rendered pixels.
✕ ""Every group of links needs to be wrapped in nav""
nav is meant for genuine navigation blocks — a primary menu, breadcrumbs, pagination. A handful of related links inside an article's body content does not need, and generally should not have, a nav wrapper.
✕ ""main can be used more than once if a page has multiple important sections""
main should appear exactly once per page, wrapping the content unique to that specific page. Multiple prominent sections belong inside a single main as separate section or article children, not as multiple separate main elements.
// Part 09 — Interview Prep

6 Interview Questions — With Complete Answers

What is the difference between section and article, and how would you decide between them?
article is for content that would make full sense on its own if extracted and republished elsewhere — a blog post, a news story, a single product card. section is a thematic grouping WITH its own heading that forms one part of a larger document, but does not necessarily stand alone. A useful test: could this content be pulled out and syndicated on its own and still make complete sense? If yes, article. If it only makes sense as one labeled part of a bigger whole, section.
Why is a heading hierarchy that skips levels (h2 straight to h4) considered a real problem, not just a style nitpick?
Screen reader users frequently navigate a page by heading level, jumping directly between headings of a given rank. A skipped level breaks that navigation model and misrepresents the page's actual logical structure — it also confuses tools and browser extensions that generate an automatic table of contents from the heading hierarchy. It should be treated as a structural bug, not a visual preference.
What is "div soup," and why can it be invisible during normal manual testing?
Div soup is a page built almost entirely from generic div elements, with CSS classes doing all the labeling instead of using HTML's actual semantic and landmark elements. Because CSS can style a div to look identical to a properly semantic element, the page can look completely correct to anyone testing it visually. The problem only becomes visible to tools that read the underlying elements rather than rendered pixels — screen readers, search engine crawlers, and accessibility audit tools.
Should main ever appear more than once on a page? What about header and footer?
main should appear exactly once, wrapping the content unique to that specific page. header and footer, by contrast, can legitimately appear more than once, since they can be scoped to an individual article or section (e.g. a blog post's own byline header) in addition to, or instead of, the page-level header and footer.
What is the document outline, and what two things does it depend on together?
The document outline is the logical, tree-shaped structure of a page implied by its headings and semantic landmark elements together — it is what screen-reader heading navigation, browser reading modes, and search engines use to understand a page's shape. It depends on both pieces together: a correct heading hierarchy inside unlabeled divs still leaves landmarks undiscoverable, and correct landmarks with a broken heading order still leave the content within them unclear.
Give an example of when using a plain div is still the semantically correct choice, even in an otherwise well-structured page.
A purely visual grouping — for example, a wrapper div applying a CSS Grid layout to a set of already-semantic card elements — that has no heading of its own and represents no distinct thematic unit of content. Reaching for section in that situation, without a heading, adds structure the document does not actually have; div is the honest, correct element for a grouping that exists solely for styling or layout purposes.
// Common Mistakes

Semantic Structure Mistakes Beginners Make Constantly

Choosing a heading level for its default font size instead of its logical position
This breaks the document outline while looking fine visually. Fix the size with CSS instead — h3 { font-size: ... } — and choose the heading level based purely on where it sits in the page's logical structure.
Wrapping every block of text in a div instead of a p
Actual paragraphs of prose should be <p>, not <div>. This affects screen-reader navigation, default spacing, and how search engines and readability tools identify real body text on the page.
Using section as a generic wrapper with no heading inside it
section specifically means a thematic unit with its own heading. A grouping with no heading of its own is a div — using section without a heading adds structure to the outline that does not actually exist.
Wrapping every small cluster of links in nav
nav is meant for genuine navigation — primary menus, breadcrumbs, pagination. A few related links inside an article body do not need a nav wrapper; a plain list, or even just inline links, is the correct choice there.
Using multiple main elements on a single page
main should appear exactly once, holding the page-specific primary content. Multiple prominent content blocks should be separate section or article elements nested inside that single main, not multiple main elements side by side.
// Error Library

Errors and Audit Warnings You Will Hit — And Exactly Why

Lighthouse / axe: "Heading levels should only increase by one"
Cause: A heading skips one or more levels, most often h2 straight to h4, usually because a smaller heading's default font size looked more appropriate for the design than the correct next level.
Fix: Use the correct next heading level for the document's logical structure, and adjust its visual size independently with CSS if the default doesn't match the design.
Lighthouse / axe: "Document should have one main landmark"
Cause: The page either has no <main> element at all, or has more than one — both violate the expectation that main wraps exactly one primary content region per page.
Fix: Add a single <main> wrapping the page-specific content, distinct from header, nav, and footer. If multiple main elements exist, consolidate the real content into exactly one and convert the others to section or article.
Screen reader announces the whole page as one undifferentiated block with no landmarks
Cause: The page is built from div soup — generic div elements with CSS classes standing in for header, nav, main, and footer instead of the real semantic elements.
Fix: Replace class-labeled div wrappers with the actual semantic elements they represent — header, nav, main, footer — as covered in Part 05.
Lighthouse: "Heading elements are not in a sequentially-descending order"
Cause: Same root cause as the heading-skip warning above, but can also occur from headings appearing visually out of their logical DOM order, or from a component being reused at different nesting depths without adjusting its heading level.
Fix: Trace the actual heading sequence in DOM order (not visual order) and correct any level that breaks the one-step-at-a-time descent.
A browser reading-mode / "reader view" feature fails to extract the article, or extracts the wrong content
Cause: Reader-mode extraction relies on finding an <article> (or a clearly identifiable main content region) — a page built entirely from unlabeled divs gives it nothing reliable to identify as the actual article content.
Fix: Wrap the primary readable content in a real <article> element inside <main>, keeping navigation, sidebars, and footer content outside of it.

🎯 Key Takeaways

  • Heading levels (h1-h6) express the logical outline of a page, not a font-size shortcut — never pick a level for its default size; style it with CSS instead.
  • Never skip a heading level. Convention is exactly one h1 per page, representing the page's single main topic.
  • Use <p> for actual readable prose, <div> for a generic, meaning-free grouping used purely for styling or layout.
  • "Div soup" — a page built entirely from generic divs with CSS classes standing in for real structure — can look pixel-identical to well-structured HTML while being invisible or broken to screen readers, search engines, and reading-mode tools.
  • The landmark elements (header, nav, main, footer) replace class-labeled divs with real, machine-recognizable structure. main appears exactly once per page; header and footer can be scoped to individual articles/sections too.
  • article is content that makes full sense standalone; section is a thematic grouping WITH its own heading, forming part of a larger whole; aside is related-but-skippable content. A grouping with no heading of its own is correctly a plain div, not a section.
  • The document outline — built from headings and landmarks together — is what screen readers, reading-mode extraction, and search engines actually use to understand a page's shape.

What comes next

Module 04 covers the anchor tag in full — every href value type, the security implications of target="_blank", linking to a specific point within a page, and building a real, semantic navigation menu.

Module 04 → Links and Navigation
Share

Discussion

0

Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.

Continue with GitHub
Loading...