Summit Themes
Blog

The power of HTML semantic tags

Every HTML element you write sends a signal. A <div> says "I am a box." A <nav> says "I am the site's navigation." That distinction sounds small until you realize it affects whether a screen reader announces your page correctly, whether Google understands your document structure, and whether a browser's reader mode extracts the right content. Semantic HTML is the practice of choosing the element that accurately describes its content, not just the one that looks right on screen.

This post walks through the core semantic tags introduced or clarified by HTML5, explains when to reach for each one, and shows the patterns that come up most often in real projects.

What "semantic" actually means

A semantic element has inherent meaning baked into the tag name itself. Compare these two snippets — they produce identical visual output in a browser:

<!-- Non-semantic -->
<div class="nav">
  <div class="nav-item"><a href="/about">About</a></div>
</div>

<!-- Semantic -->
<nav aria-label="Main">
  <ul>
    <li><a href="/about">About</a></li>
  </ul>
</nav>

The first version requires you to read the class names to understand the intent. The second version communicates intent through the element itself — a screen reader will announce "Main navigation, list, 1 item" without any extra ARIA configuration. The tag does the work.

The structural landmarks

These elements divide a page into regions that assistive technologies expose as "landmark" navigation points. Users of screen readers can jump between them the same way sighted users scan visually.

<header>

A <header> represents introductory content. It can appear at the document level (the site masthead) or inside any sectioning element. A blog post can have its own <header> containing the title, author, and publish date — that is valid and useful.

<body>
  <header>
    <a href="/" aria-label="Summit Themes home">
      <img src="/logo.svg" alt="Summit Themes" width="140" height="32">
    </a>
    <nav aria-label="Main">...</nav>
  </header>

  <main>
    <article>
      <header>
        <h1>The power of HTML semantic tags</h1>
        <p>By Jane · <time datetime="2026-06-22">June 22, 2026</time></p>
      </header>
      ...
    </article>
  </main>
</body>

<nav>

Reserve <nav> for major navigation blocks: the site menu, a table of contents, breadcrumbs. Not every group of links qualifies. A footer full of legal links is fine without <nav>. When you do use multiple <nav> elements on one page, give each a distinct aria-label so assistive technologies can tell them apart.

<main>

There must be exactly one <main> per page. It wraps the content that is unique to that document — not the header, not the footer, not a sidebar shared across every page. Browsers use it for the "skip to content" link target, and search engines treat it as the primary content region. If your layout has a sticky header, wire your skip link to #main-content and put id="main-content" on the <main> element.

<footer>

Like <header>, <footer> can live at the document level or inside a section. A document-level footer typically holds copyright, links, and contact information. An <article> footer might hold author bio, tags, or a "last updated" timestamp. Both uses are correct.

<aside>

<aside> marks content that is tangentially related to the surrounding content. Classic uses: a sidebar, a pull quote, an ad unit, a "related posts" block. When placed inside an <article>, it should relate to that article specifically. When placed as a sibling of <main>, it relates to the page broadly.

Content sectioning: article, section, and the div question

This is where most developers get tangled. The three elements look interchangeable but have meaningfully different scopes.

<article>

An <article> is self-contained and independently distributable. If you yanked it out of the page and dropped it into an RSS feed, an email, or another site, it would still make complete sense. Blog posts, news stories, product cards in a listing, user-submitted comments — all are legitimate <article> candidates. Articles can nest: a comments section containing individual comment articles inside a post article is valid.

<section>

A <section> is a thematic grouping of content that belongs to the document but is not independently meaningful. A long landing page broken into "Features," "Pricing," and "Testimonials" blocks — those are sections, not articles, because they only make sense in context. The spec guidance is practical: if you cannot think of a heading for the block, consider whether a <div> fits better.

<div>

<div> carries no semantic meaning. It is a pure layout or scripting hook. Use it when you need a wrapper for CSS (a flex or grid container, a positioning context) and no semantic element applies. The goal is not to eliminate every <div> — it is to not use a <div> when a semantic element is the right call.

<!-- A blog listing: each post is self-contained → article -->
<main>
  <h1>Latest Posts</h1>
  <article>
    <h2><a href="/posts/semantic-html">The power of HTML semantic tags</a></h2>
    <p>Every element you write sends a signal...</p>
  </article>
  <article>
    <h2><a href="/posts/tailwind-v4">Getting started with Tailwind CSS v4</a></h2>
    <p>Tailwind v4 moves configuration into CSS...</p>
  </article>
</main>

<!-- A services page: sections within the page context -->
<main>
  <section>
    <h2>What we offer</h2>
    <p>...</p>
  </section>
  <section>
    <h2>How it works</h2>
    <p>...</p>
  </section>
</main>

Inline semantic elements worth knowing

The structural landmarks get most of the attention, but these inline elements do real work too.

<time>

The <time> element marks up dates and times in a human-readable form while providing a machine-readable datetime attribute. Search engines use it to understand publication dates; calendar apps can parse it; voice assistants can read it accurately.

<p>Published <time datetime="2026-06-22">June 22, 2026</time></p>

<!-- For durations, use the ISO 8601 duration format -->
<p>Build time: <time datetime="PT2M34S">2 minutes and 34 seconds</time></p>

<figure> and <figcaption>

<figure> wraps self-contained content that is referenced from the main flow — images, code listings, charts, diagrams. <figcaption>, when present, provides the caption and must be the first or last child of the figure. Screen readers associate the caption with the content automatically, which is more reliable than a plain <p> placed nearby.

<figure>
  <pre><code>const greet = (name) => `Hello, ${name}!`;</code></pre>
  <figcaption>A simple ES2015 arrow function returning a template literal.</figcaption>
</figure>

<address>

<address> marks contact information for the nearest <article> or <body> ancestor. It is for contact details — name, email, phone, postal address — not arbitrary addresses. Search engines understand it as a contact signal, and it maps well to the LocalBusiness schema type.

<footer>
  <address>
    <strong>Aircrest HVAC</strong><br>
    <a href="tel:+15551234567">(555) 123-4567</a><br>
    Phoenix, AZ 85001
  </address>
</footer>

<mark>, <strong>, and <em>

<mark> highlights text for reference purposes (think search results highlighting the query term). <strong> signals importance — the browser bolds it by default, and screen readers may stress it. <em> signals emphasis that changes the meaning of a sentence, the way you'd stress a word in speech. Both differ from <b> and <i>, which are stylistic-only with no semantic weight.

The heading hierarchy: one rule that matters most

None of the structural elements above replace the most fundamental semantic decision you make on every page: heading order. Use one <h1> per page (the document title), then <h2> for major sections, <h3> for subsections, and so on. Never skip levels for visual sizing reasons — use CSS for that. A screen reader user navigating by headings relies on this hierarchy the same way a sighted user relies on visual weight.

<!-- Good: logical hierarchy -->
<h1>HVAC Services in Phoenix</h1>
  <h2>Residential AC Repair</h2>
    <h3>Same-Day Service</h3>
  <h2>Commercial HVAC</h2>

<!-- Bad: skipping h2 for visual reasons -->
<h1>HVAC Services in Phoenix</h1>
  <h3>Residential AC Repair</h3> <!-- skipped h2 → broken outline -->

Why it matters beyond accessibility

Accessibility is the primary reason to use semantic HTML, but it is not the only one. Search engines increasingly rely on semantic signals — landmark regions, heading hierarchies, <article> boundaries, <time> attributes — to understand and summarize content. Browser reader modes (Safari Reader, Firefox Reader View) depend on them to strip chrome and extract the article body. Developer tooling, automated testing, and scraping scripts all get faster and more reliable when the structure is honest. And your own team benefits: a codebase full of nested <div>s is harder to read than one where <nav>, <main>, and <article> tell you instantly what each region is.

A quick decision guide

  • Self-contained, independently distributable content? Use <article>.
  • A thematic grouping within the page that needs a heading? Use <section>.
  • Pure layout wrapper, no semantic meaning? Use <div>.
  • The site masthead or a content block's intro? Use <header>.
  • A major navigation block? Use <nav> with aria-label.
  • The unique content of the page? Use <main> — exactly once.
  • Tangentially related content or a sidebar? Use <aside>.
  • A date or time value? Use <time datetime="...">.
  • An image, diagram, or code listing with a caption? Use <figure> and <figcaption>.
  • Contact information? Use <address>.

Semantic HTML is not a checklist you run through once — it is a habit of asking "what is this content, not just what should it look like?" that makes every page you ship more durable, more accessible, and easier to maintain. The tags exist precisely so you do not have to encode meaning in class names or comments. Let them do their job.