Chapter 1: Semantic HTML That Means Something
Why structure isn’t just for the browser: it’s for people, machines, and the future of the web.
If you’re a front-end engineer who still uses <div class="container">
for everything, this chapter is your turning point. Semantic HTML isn’t just a legacy convention from the early 2000s. It’s how modern browsers, assistive technologies, and search engines understand your interface.
This chapter teaches you how to structure real content using native HTML semantics. Not because the spec says so, but because it fundamentally improves accessibility, maintainability, and performance.
Think of it like this: You can either write HTML that works by accident, or HTML that communicates meaning by design. The latter is how you level up.
Section 1.1: Tags That Mean Things, Not Just Boxes
Most websites today are written in “div”. Containers within containers, styled into oblivion, but completely void of meaning. The browser renders it, but assistive tech? Lost.
The browser creates a DOM tree but only semantic HTML elements contribute to the Accessibility Tree, which is what screen readers and assistive tools actually use.
Let’s walk through HTML tags that carry meaning what they do, when to use them, and why they matter.
<main>
: The Primary Landmark
Represents the dominant content of the <body>
of the document.
There should be only one per page, and it must be unique.
Why it matters:
Screen readers let users skip directly to the <main>
region. Without it, keyboard users are left to manually tab past every nav and sidebar.
<main>
<h1>My Product Page</h1>
<p>This is what you're here to read.</p>
</main>
<section>
: Grouping Thematically Related Content
Think of <section>
as a way to break up the outline of your document.
It’s appropriate if the content:
- Has its own heading
- Represents a standalone block within the page
Bad usage:
<section class="wrapper"><!-- used just for layout --></section>
Good usage:
<section>
<h2>Customer Testimonials</h2>
<blockquote>“This changed how I code.”</blockquote>
</section>
<article>
: Reusable, Syndicatable Content
Use when the content can stand alone like:
- Blog posts
- Product reviews
- Comments
- News feeds
Screen readers interpret articles as navigable regions, and some even let users jump from article to article using shortcut keys.
<article>
<h2>Building a Modern Layout System</h2>
<p>Flexbox and Grid aren’t enemies,they’re partners.</p>
</article>
<aside>
: Supplementary Info
Used for tangential content like:
- Tips
- Quotes
- Ads
- Sidebars
<aside>
<h3>Did you know?</h3>
<p>The `<aside>` element is still announced by screen readers.</p>
</aside>
Don’t use this for essential information. If it’s critical to the main content, it belongs in the <main>
or <section>
.
<nav>
Structured Navigation Landmark
If your links take you somewhere, they go in a <nav>
.
This creates a navigable landmark for screen readers.
<nav aria-label="Main site navigation">
<ul>
<li><a href="/about">About</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</nav>
Pro tip: Always label your <nav>
with aria-label
if you have more than one navigation block.
<header>
and <footer>
: Section-Level and Global
These elements define the intro and outro of a page or any section/article.
<article>
<header><h2>JS: The Good Parts Still Worth Using</h2></header>
<p>There’s still a lot of signal in the noise.</p>
<footer><p>Posted by Idil</p></footer>
</article>
Don’t confuse global layout with document structure. Use these elements to describe structure within your content, not to force layout.
Section 1.2: Real-World Form Semantics
Forms are a minefield of accessibility issues. Here’s what a proper, semantically correct form looks like:
<form>
<fieldset>
<legend>Newsletter Signup</legend>
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required aria-describedby="email-note" />
<div id="email-note">We'll send cool stuff. No spam.</div>
<button type="submit">Subscribe</button>
</fieldset>
</form>
Why this works:
<label>
is connected to its input usingfor="id"
.<fieldset>
and<legend>
group related inputs and give screen readers context.aria-describedby
provides supplementary instructions, read aloud after focus.required
triggers native validation which works better than you think.
Most developers still get this wrong:
- Using
placeholder
instead of<label>
which disappears on focus and isn’t accessible. - Styling instead of structuring, putting help text visually near fields but never describing it with ARIA.
- Omitting
fieldset
when grouping radio buttons or checkboxes.
Section 1.3: ARIA Roles and When You Actually Need Them
Let me say something controversial but true:
If you’re using ARIA in place of native HTML, you’re probably doing it wrong.
ARIA is powerful but it’s meant to fill the gaps in native HTML, not replace it.
When to use ARIA:
- You’re building custom components (tabs, accordions, modals)
- You need live announcements (
aria-live
) - You need to manually toggle state (
aria-expanded
,aria-hidden
) - You’re linking help text or label context (
aria-describedby
,aria-labelledby
)
When not to:
- Don’t add
role="button"
to a<div>
just use<button>
- Don’t add
role="navigation"
to a generic container use<nav>
<!-- Incorrect -->
<div role="button" onclick="...">Click me</div>
<!-- Correct -->
<button type="button">Click me</button>
References & Recommended Reading
- W3C HTML Element Reference
- MDN Web Docs: HTML Semantics
- WebAIM: Semantic Structure
- WAI-ARIA Authoring Practices Guide
What’s Next
In Chapter 2, we’ll dig into how the browser builds the DOM Tree, how it translates that into the Accessibility Tree, and how to inspect both like a true expert.
The difference between visible layout and semantic structure is critical and most developers have never seen what assistive tech actually sees.
Let’s change that.