FullStack Course LogoFullStack Course
Module: HTML
HTML·006·11 MIN READ

006: Semantic HTML

TOPICS COVERED: Semantic HTML

Learning outcomes

By the end of this lesson, you can choose header, nav, main, section, article, aside, and footer because of what their content means. You can also explain when div and span are still the right choice, identify the landmarks a page exposes, and refactor a wrapper-heavy portfolio without adding ARIA that merely repeats native HTML.

Prerequisites and retrieval

Start with the portfolio from 005. Without opening its source, name its major visual regions. Then recall the difference between a heading selected for document hierarchy and one selected only because its appearance is convenient. Semantic regions use the same rule: choose meaning first, and use CSS for appearance.

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 labeled only “box 1, box 2” makes every reader infer what each room is for. Labels such as “entrance,” “kitchen,” and “office” communicate intent immediately. Semantic elements provide those useful labels for a document. They help maintainers, browsers, search systems, reader modes, and assistive technologies, although semantics alone do not guarantee search ranking or complete accessibility.

Choose the element whose definition fits the content, rather than the element whose default browser styling happens to resemble the design. Without CSS, most structural elements still look like ordinary blocks. Their important output is the meaning they expose, not their default appearance.

Structural elements

header represents introductory content or navigational aids for its nearest section. A page-level header may contain site identity and navigation, while an article header might contain that article's title and date. Not every header is the page's banner landmark.

nav identifies a section whose purpose is navigation. Reserve it for meaningful groups of navigation links rather than wrapping every small cluster of links. A list is often a good structure inside it.

main contains the document's dominant, page-specific content. A normal page has one visible main; it should not be placed inside article, aside, header, footer, or nav.

section groups related content around a theme and will generally have a heading. It is not a universal wrapper. If you cannot give the grouping a meaningful name, a div may describe the markup more honestly.

article represents a self-contained composition, such as a post, project entry, product card, or comment, that could stand on its own. Nested article elements can represent comments belonging to an article.

aside holds content that is tangentially related to its surrounding content. At page level it may expose a complementary landmark; inside an article it might be a related note. The fact that something appears in a right-hand column does not, by itself, make it an aside.

footer contains footer information for its nearest section, such as an author, related links, copyright, or metadata. A page-level footer commonly maps to content information, but a footer belonging to an article does not automatically become a page landmark.

div and span have no special meaning. That is not a defect. Use them when styling or scripting needs a grouping and no semantic element applies: div for flow content and span for phrasing content. Choosing a semantic element inaccurately does not create meaning; it creates a misleading document.

Landmark and sectioning rules in real pages

The boundaries matter more than the visual layout:

  • A document should normally expose one primary main landmark. Repeated site chrome, including the header, navigation, and footer, sits outside it.
  • A page may contain several nav elements when they represent meaningful navigation groups. If multiple navigation landmarks are present, 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. It is not a generic replacement for every div.
  • Use article when content can reasonably stand alone or be distributed independently, such as a news story, forum post, product review, or blog entry.
  • aside is complementary to the surrounding content. It does not mean “the right-hand column.”
  • header and footer may belong to the entire page or to an individual section or article. They are not limited to one occurrence per document.

There is no goal of eliminating div and span. They are correct whenever no more specific meaning fits. The useful question is not “Which tag looks most semantic?” but “Which element's defined meaning matches this content?”

Native disclosure, dialog, and status semantics

Semantic HTML applies to interactions and status displays as well as page regions. The platform already provides elements for several common patterns. Start with those native semantics before rebuilding the interaction from generic div elements.

details and summary

details represents a disclosure widget, and its first summary child supplies 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 supplies keyboard-operable open and close behavior without JavaScript.

The open attribute records 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 that someone must see to understand or complete a critical task.

One common mistake is to replace summary with a clickable div. That throws away the native keyboard and accessibility behavior instead of improving the markup.

dialog

dialog represents a dialog or another 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 gives you the element, but opening a modal normally requires JavaScript:

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

The division of responsibility is worth keeping clear:

  • 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 turn an arbitrary container into a modal by adding role="dialog" while leaving keyboard interaction and focus behavior unfinished. Native dialog is usually the stronger starting point.

progress

Use progress to represent how much of a task is complete:

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

When the current amount is unknown, omit value:

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

That produces an indeterminate progress indicator.

Do not use progress for an arbitrary score, capacity, or measurement. Its meaning is 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>

Disk usage, a rating, battery level, and a measured value with meaningful bounds are all reasonable examples.

progress and meter answer different questions:

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

Give either one visible context with a label or surrounding text. A bar that has no communicated meaning is not enough.

Guided example: compare generic and semantic structure

Here is a portfolio fragment before the refactor:

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 class names suggest a visual intention, but the markup exposes none of that structure. There is no actual heading and no major landmark for assistive technology or other consumers to use.

Now compare a semantic version:

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>

Native elements supply most of the ARIA here, so additional roles would only repeat what is already present. The heading gives the section a clear visible topic without promoting every section to a named region landmark. In particular, do not add role="main" to main, role="navigation" to nav, or role="article" to article.

Refactor from the outside inward. Find the page-wide header, navigation, unique main content, and footer first. Within main, identify genuine thematic sections and independent articles. Then review the headings. The hierarchy of the headings should support the semantic boundaries rather than contradict them.

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 called “hero”; HTML has no hero element. The project is an article because the project summary can stand on its own. “Currently learning” is related but secondary, so aside is a reasonable choice. If that material becomes core content, it should become a section instead.

The section around h1 could also be omitted, with the heading placed directly in main. Semantic choices require judgment; they are not a contest to maximize the number of special elements. Prefer the smallest structure that accurately describes the content.

Advanced optional extension: inspect the accessibility tree

Open your browser's accessibility tools and inspect the landmarks. Depending on the browser's mappings, expect a banner for the page header, a navigation landmark named Primary, main, a complementary landmark for the page-level aside, and content information for the page footer. If a screen reader is available, try navigating with its landmark shortcuts.

Add a second nav in the footer and observe the problem: two unnamed navigation landmarks are difficult to distinguish. Label them with visible headings via aria-labelledby where that helps everyone, or with concise values such as “Primary” and “Footer” via aria-label. Do not label every section; a page with too many landmarks becomes noisy rather than clearer.

Common mistakes and debugging

  • Replacing every div with section: use section for a named theme, not as a styling hook.
  • Choosing aside by screen position: decide whether the content is related but secondary.
  • 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 tells the truth about the content.
  • Site logo made h1 on every page: the heading should describe each document's main content.
  • Redundant roles: native HTML already supplies these semantics.
  • Assuming semantic HTML guarantees SEO/accessibility: it is a strong foundation, not a complete audit.

Accessibility, security, and performance

Landmarks let people bypass repeated blocks and move directly to the main content. Heading labels make regions easier to understand. Keep repeated navigation consistent, and keep source order meaningful rather than relying on visual positioning to repair a confusing reading order. Native semantics are generally more robust and require less code than recreated ARIA widgets. Remember that ARIA changes accessibility APIs; it does not supply keyboard behavior. “No ARIA is better than bad ARIA.”

Semantics do not sanitize content. External links, user-provided text, and media still need security and privacy review. Lean native markup can reduce wrapper count and script dependencies, but that performance benefit is secondary to choosing the right meaning. Do not remove a wrapper that serves a real purpose just 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 choice.

Level 2: refactor

Refactor one portfolio page into a page header, primary navigation, main, at least one named section, one project article, and a footer. Preserve its 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 the actual content.

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

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 semantic meaning fits.

  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

The element choices become easier to judge after you have deliberately made a wrong one, so apply the same reasoning to a page you have not seen before.

Here is a fragment inherited from an earlier draft of Rina's homepage:

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 further, decide which of header, nav, main, section, article, aside, or footer belongs on each line, or whether plain div is the better choice. More importantly, write down why. Then compare your reasoning with this version:

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 choice is the promo box. It became article, not aside, because on a one-page weekly-special site it is the dominant content, not a tangential note. If Rina later adds a full menu page, the same block might move into an aside there. The skill is not memorizing which tag “means” promo; it is asking what role this content plays on this particular page.

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

Official references

Reader page: /html/lesson/006/semantic-html