Module: HTML
HTML·006·10 MIN READ

006: Semantic HTML

TOPICS COVERED: Semantic HTML

Learning outcomes

By the end of this lesson, you can select header, nav, main, section, article, aside, and footer by meaning; explain when div and span remain appropriate; identify page landmarks; and refactor a generic wrapper-heavy portfolio without adding redundant ARIA.

Prerequisites and retrieval

Use the 005 portfolio. List its major visual regions without looking at source. Then retrieve the difference between a heading chosen for hierarchy and one chosen for appearance. Semantic regions follow the same rule: meaning first.

Terminology

  • Semantics: Meaning conveyed by markup independent of visual presentation. — Source: MDN: Glossary — Semantics
  • Landmark: Major page regions (banner, navigation, main, complementary, contentinfo) exposed for assistive navigation. — Source: W3C WAI: Page structure concepts
  • Sectioning content: article, aside, nav, and section define sections within the document outline. — Source: WHATWG: Sections
  • Generic container: div (flow) and span (phrasing) group content without adding any meaning. — Source: WHATWG: The div element
  • Accessible name: The programmatic label exposed to assistive technology for an element or region. — Source: ARIA APG: Read Me First
  • Document outline: The heading-derived structure of a page; browsers do not implement the old automatic outline algorithm. — Source: WHATWG: Sections and headings
  • Self-contained: Content meaningful when distributed alone — the criterion for using article. — Source: WHATWG: The article element
  • Semantic HTML: "Using elements for their meaning, not appearance." — Source: MDN: Structuring documents
  • Header (header): "The header element represents introductory content, typically a group of introductory or navigational aids." — Source: WHATWG: Sections — header
  • Navigation (nav): "The nav element represents a section of a page whose purpose is to provide navigation links." — Source: WHATWG: Sections — nav
  • Main (main): "The main element represents the dominant contents of the document." — Source: WHATWG: Grouping content — main

Mental model: label rooms by purpose

A building plan marked only “box 1, box 2” forces every reader to infer purpose. “Entrance, kitchen, office” communicates intent. Semantic elements do that for a document. They help maintainers, browsers, search systems, reader modes, and assistive technologies, although semantics do not guarantee ranking or full accessibility.

Use the element whose definition matches the content, not one whose default styling resembles your design. Most structural elements look like generic blocks without CSS. Their value is meaning.

Structural elements

header represents introductory or navigational aids for its nearest section. A page-level header often contains site identity and navigation; an article header can contain its title and date. Not every header is the page's banner landmark.

nav represents a section whose purpose is navigation. Use it for major groups, not every cluster of links. A list is often suitable inside it.

main contains the dominant content unique to the document. A normal page has one visible main; do not place it inside article, aside, header, footer, or nav.

section is a thematic grouping, generally with a heading. It is not a universal wrapper. If you cannot name the section, a div may be more honest.

article is self-contained composition such as a post, project entry, product card, or comment that could stand independently. Nested articles can represent comments on an article.

aside contains content tangentially related to surrounding content. At page level it may expose a complementary landmark; inside an article it can be a related note. It does not simply mean “right column.”

footer contains footer information for its nearest section: author, related links, copyright, or metadata. A page-level footer commonly maps to content information; article footers do not all become page landmarks.

div and span carry no special meaning. That is not inherently bad. Use them for grouping needed by styling or scripting when no semantic element applies. Do not invent meaning by choosing a semantic element inaccurately.

Landmark and sectioning rules in real pages

Semantic elements are most useful when you understand their boundaries:

  • A document should normally have one primary main landmark. Repeated site chrome such as the header, navigation, and footer sits outside it.
  • A page can contain multiple nav elements when they represent meaningful navigation groups. If several navigation landmarks exist, give them distinguishable accessible names, for example with aria-label or aria-labelledby.
  • Use section for a thematic grouping that would normally deserve a heading. A section is not a generic replacement for every div.
  • Use article for content that can reasonably stand on its own or be distributed independently: a news story, forum post, product review, or blog entry.
  • aside is complementary to the surrounding content. It is not simply “the right-hand column.”
  • header and footer can belong to the entire page or to a section/article. They are not restricted to one occurrence per document.

Semantic HTML does not require eliminating div and span. Those generic elements are correct when no more specific meaning exists. The goal is not “use the most semantic-looking tag”; the goal is “use the element whose defined meaning matches the content.”

Native disclosure, dialog, and status semantics

Semantic HTML is not limited to page regions. The platform also provides elements for common disclosure, dialog, and status patterns. Prefer these native semantics before rebuilding the same interaction from generic div elements.

details and summary

details represents a disclosure widget. Its first summary child provides the visible label.

html
<details>
  <summary>Delivery information</summary>
  <p>Orders placed before 3 PM are processed the same business day.</p>
</details>

The browser provides keyboard-operable open/close behavior without JavaScript.

The open attribute represents the current state:

html
<details open>
  <summary>Course prerequisites</summary>
  <ul>
    <li>Basic HTML</li>
    <li>A modern browser</li>
  </ul>
</details>

Use a disclosure when the content is optional or secondary. Do not hide information users must see to understand or complete a critical task.

A common mistake is replacing summary with a clickable div. That discards native keyboard and accessibility behavior.

dialog

dialog represents a dialog or other temporary window.

html
<dialog id="confirm-delete">
  <h2>Delete project?</h2>
  <p>This action cannot be undone.</p>

  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Delete</button>
  </form>
</dialog>

HTML provides the element, but opening a modal dialog normally happens through JavaScript:

js
document.querySelector("#confirm-delete").showModal();

The important HTML lesson is the division of responsibility:

  • HTML provides the correct dialog element and meaningful content;
  • JavaScript controls application behavior;
  • CSS controls presentation;
  • focus management and accessible labeling still need deliberate testing.

Do not simulate a modal by placing role="dialog" on an arbitrary container while leaving keyboard interaction and focus behavior incomplete. Native dialog is usually the stronger starting point.

progress

Use progress for the completion progress of a task:

html
<label for="upload-progress">Uploading files</label>
<progress id="upload-progress" value="62" max="100">62%</progress>

If the current amount is unknown, omit value:

html
<progress aria-label="Preparing report"></progress>

That represents indeterminate progress.

Do not use progress for an arbitrary score, capacity, or measurement. It represents task completion.

meter

Use meter for a scalar measurement within a known range:

html
<label for="storage">Storage used</label>
<meter
  id="storage"
  min="0"
  max="100"
  low="60"
  high="85"
  optimum="30"
  value="72"
>
  72%
</meter>

Examples include disk usage, a rating, battery level, or a measured value with meaningful bounds.

progress and meter are not interchangeable:

QuestionElement
How much of a task is complete?progress
What is the current measurement inside a known range?meter

Always provide visible context with a label or surrounding text. A graphical bar without meaning is not sufficient communication.

Guided example: compare generic and semantic structure

Before:

html
<div class="top">
  <div>Asha Rao</div>
  <div class="links">
    <a href="index.html">Home</a>
    <a href="about.html">About</a>
  </div>
</div>
<div class="content">
  <div class="title">Asha's projects</div>
  <div class="project">
    <div class="project-title">Weather summary</div>
    <p>A semantic prototype.</p>
  </div>
</div>
<div class="bottom">Copyright 2026 Asha Rao</div>

The visual class names hint at meaning, but the HTML does not expose it. There is no real heading or major landmark.

After:

html
<header>
  <p>Asha Rao</p>
  <nav aria-label="Primary">
    <ul>
      <li><a href="index.html" aria-current="page">Home</a></li>
      <li><a href="about.html">About</a></li>
    </ul>
  </nav>
</header>
<main>
  <h1>Asha's projects</h1>
  <section>
    <h2>Featured work</h2>
    <article>
      <h3>Weather summary</h3>
      <p>A semantic prototype.</p>
      <p><a href="projects/weather.html">Read about the weather project</a></p>
    </article>
  </section>
</main>
<footer>
  <p><small>Copyright 2026 Asha Rao</small></p>
</footer>

Most ARIA is unnecessary because native elements already provide roles. The heading gives the section a clear visible topic without promoting every section to a named region landmark. Do not add role="main" to main, role="navigation" to nav, or role="article" to article.

Work top down. Identify page-wide header, navigation, unique main content, and footer. Then identify actual thematic sections and independent articles. Finally check headings. Semantics and heading hierarchy must agree.

Intermediate example: complete portfolio architecture

html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Home | Asha Rao</title>
  </head>
  <body>
    <header>
      <p>Asha Rao</p>
      <nav aria-label="Primary">
        <ul>
          <li><a href="index.html" aria-current="page">Home</a></li>
          <li><a href="about.html">About</a></li>
          <li><a href="contact.html">Contact</a></li>
        </ul>
      </nav>
    </header>
    <main>
      <section>
        <h1>Building accessible, semantic interfaces</h1>
        <p>I build small projects with meaningful HTML.</p>
      </section>
      <section>
        <h2>Projects</h2>
        <article>
          <h3>Weather summary</h3>
          <p>A page that explains local forecast data.</p>
          <p><a href="projects/weather.html">Weather project details</a></p>
        </article>
      </section>
      <aside aria-labelledby="learning-heading">
        <h2 id="learning-heading">Currently learning</h2>
        <p>Accessible forms and robust validation.</p>
      </aside>
    </main>
    <footer>
      <p><a href="contact.html">Contact Asha</a></p>
    </footer>
  </body>
</html>

The hero-like introduction is a thematic section, not an element named “hero” because HTML has no hero element. The project is an article because it can stand as a project summary. “Currently learning” is related but secondary, so aside is reasonable. If it becomes core content, use a section instead.

The section containing h1 could be omitted and the heading placed directly in main; semantics are judgment, not a requirement to maximize element variety. The smallest correct structure is best.

Advanced optional extension: inspect the accessibility tree

Open browser accessibility tools and inspect landmarks. Expect banner (page header), navigation named Primary, main, complementary (page-level aside), and content information (page footer), depending on browser mappings. Navigate with a screen reader's landmark shortcuts if available.

Add a second nav in the footer. Both unnamed navigation landmarks become hard to distinguish. Label visible headings with aria-labelledby or concise aria-label values such as “Primary” and “Footer.” Prefer visible headings when the label is useful to everyone. Do not label every section; too many landmarks create noise.

Common mistakes and debugging

  • Replacing every div with section: use section for a named theme, not styling hooks.
  • Choosing aside by screen position: use related-but-secondary meaning.
  • Multiple visible main elements: keep one dominant region.
  • main nested in forbidden structural containers: keep it at page body level.
  • Heading-free sections: ask whether a heading or a generic wrapper is more truthful.
  • Site logo made h1 on every page: heading should describe each document's main content.
  • Redundant roles: native HTML already provides semantics.
  • Assuming semantic HTML guarantees SEO/accessibility: it is a strong foundation, not a complete audit.

Accessibility, security, and performance

Landmarks let users bypass repeated blocks and navigate directly to main content. Heading labels let users understand regions. Keep repeated navigation consistent and source order meaningful. Native semantics are more robust and require less code than recreated ARIA widgets. ARIA changes accessibility APIs, not keyboard behavior; “No ARIA is better than bad ARIA.”

Semantics do not sanitize content. External links, user-provided text, and media still require security and privacy review. Lean native markup reduces wrapper count and script dependencies, but performance benefits are secondary to meaning. Do not remove a needed wrapper solely to chase a tiny DOM metric.

Tiered exercises

Level 1: select

Choose an element for site navigation, dominant page content, a standalone project card, related reading, and a style-only grouping. Justify each.

Level 2: refactor

Refactor one portfolio page into page header, primary navigation, main, at least one named section, one project article, and footer. Preserve content and links.

Level 3: landmark audit

Inspect the accessibility tree, remove redundant roles, distinguish multiple navigation regions, and explain every remaining div or span.

Level 1: nav, main, article, aside, div (or span for phrasing content).

Level 2: the intermediate document is a complete solution. A simpler version without the introduction section is also correct if h1 and its paragraph sit directly in main. Semantic choices must follow actual content.

Level 3: expected landmarks are banner, Primary navigation, main, complementary, and content information. Remove explicit roles duplicating native elements. If adding footer navigation, name it “Footer.” A remaining div is justified only as a neutral grouping for later layout or scripting with no fitting semantic meaning.

Recap and exit questions

Semantic elements name structural purpose. Use landmarks for major regions, sections for headed themes, articles for self-contained work, asides for tangential content, and generic containers when no semantics fit.

  1. How do section and div differ?
  2. When is a project summary an article?
  3. Why does screen position not define aside?
  4. How many visible main elements should a normal page have?
  5. Why avoid redundant ARIA roles?

Try it with your own example

Semantic elements are easiest to choose correctly once you have caught yourself choosing wrong, so let's do that deliberately on a page you haven't seen before.

You inherit this fragment of Rina's homepage from an earlier draft:

html
<div class="top-bar">Rina's Kitchen — Baker Street</div>
<div class="menu-link"><a href="menu.html">See today's menu</a></div>
<div class="promo">
  <div class="promo-title">This week: cardamom buns</div>
  <p>Back by popular request, Thursdays only.</p>
</div>
<div class="bottom">© 2026 Rina's Kitchen</div>

Before reading on, decide for yourself which of header, nav, main, section, article, aside, or footer — or plain div — belongs on each line, and why. Then compare:

html
<header>
  <p>Rina's Kitchen — Baker Street</p>
  <nav aria-label="Primary">
    <ul><li><a href="menu.html">See today's menu</a></li></ul>
  </nav>
</header>
<main>
  <article>
    <h1>This week: cardamom buns</h1>
    <p>Back by popular request, Thursdays only.</p>
  </article>
</main>
<footer>
  <p><small>© 2026 Rina's Kitchen</small></p>
</footer>

The interesting call is the promo box: it became article, not aside, because for a one-page weekly-special site it is the dominant content, not a tangential note. If Rina's site later grows a full menu page, this same block might move into an aside on that page instead. That is the real skill this lesson teaches — not memorizing which tag "means" promo, but re-asking the question for each new page.

Further reading: MDN — Structuring documents works through several more before/after refactors like this one.

Official references