HTML Semantic Elements: Stop Using div for Everything
Why semantic HTML matters, what each element actually means, and when to use section vs article vs div. Plus: when you don't need ARIA because the element already handles it.
Most websites are built out of Semantic HTML fixes all of this by using elements that describe their purpose. <main> <aside> <footer> Each of these elements tells the browser (and assistive technologies) what role that content plays: Here's the rule that clears up most confusion: a <!-- Bad: no heading, no semantic meaning, just styling --> An <!-- Section within an article: thematic grouping, not independent --> Articles can contain sections. Sections can contain articles (like a "Latest Posts" section with multiple articles inside). Context matters. <figure> .
The This renders as a collapsible section. Click the summary to toggle. It's interactive HTML with zero JavaScript. Works in all modern browsers. Screen readers announce this as highlighted text. It's more meaningful than Here's something that trips people up: if you use semantic elements correctly, you often don't need ARIA attributes at all. The elements already provide the roles. <!-- Redundant: <main> already has role="main" --> <!-- Redundant: <aside> already has role="complementary" --> These are all unnecessary. The first rule of ARIA is literally: "If you can use a native HTML element with the semantics you need, do so instead of adding ARIA." ARIA is for situations where no semantic element exists for what you're building -- custom widgets, dynamic content updates, complex interactions. For standard page structure, semantic HTML does the job. One exception: Without labels, a screen reader just announces "navigation" twice. With labels, users can tell them apart. Three practical reasons: If you want to practice writing well-structured HTML with proper semantic elements, CodeUp has web development exercises that focus on building pages the right way from the start -- structure first, styling second.The Core Layout Elements
<header>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</header>
<article>
<h1>Article Title</h1>
<p>Article content...</p>
</article>
<h2>Related Links</h2>
<ul>
<li><a href="/other">Other article</a></li>
</ul>
</aside>
</main>
<p>© 2026 My Site</p>
</footer>
-- introductory content, typically contains navigation, logos, search. Can appear inside or too, not just at the page level. -- a section of navigation links. Screen readers can jump directly to it. Don't wrap every group of links in -- save it for primary navigation blocks. -- the primary content of the page. Only one per page. Screen readers use it to skip past headers and navigation. -- content tangentially related to the surrounding content. Sidebars, pull quotes, related links. Not just "stuff on the side visually." -- closing content. Copyright, contact info, secondary navigation. vs should have a heading. If you can't give it one, it's probably a <!-- Good: section has a clear theme with a heading -->
<section>
<h2>Customer Testimonials</h2>
<blockquote>Great product!</blockquote>
<blockquote>Changed my workflow.</blockquote>
</section>
<section class="wrapper">
<div class="inner">...</div>
</section>
<!-- Should just be: <div class="wrapper">...</div> --> represents a thematic grouping of content. vs is a self-contained piece of content that would make sense on its own. Blog posts, news stories, forum posts, product cards. If you could syndicate it via RSS and it would still be coherent, it's an article.<!-- Blog post: self-contained, makes sense independently -->
<article>
<header>
<h2>Understanding Flexbox</h2>
<time datetime="2026-03-26">March 26, 2026</time>
</header>
<p>Flexbox is a one-dimensional layout model...</p>
</article>
<article>
<h2>CSS Layout Methods</h2>
<section>
<h3>Flexbox</h3>
<p>...</p>
</section>
<section>
<h3>Grid</h3>
<p>...</p>
</section>
</article>Elements People Forget About
and -- not just for images:
<figure>
<pre><code>const x = 42;</code></pre>
<figcaption>A simple variable declaration in JavaScript</figcaption>
</figure>
<img src="chart.png" alt="Sales growth chart showing 40% increase">
<figcaption>Q4 2025 sales growth by region</figcaption>
</figure> wraps self-contained content that's referenced from the main flow. provides the caption. This is more meaningful than -- machine-readable dates:
<time datetime="2026-03-26">March 26, 2026</time>
<time datetime="14:30">2:30 PM</time>
<time datetime="P3D">3 days</time>datetime attribute gives browsers and search engines an unambiguous value while you display whatever format you want to humans. and -- native disclosure widget, no JavaScript needed:
<details>
<summary>Show system requirements</summary>
<ul>
<li>Python 3.9+</li>
<li>4GB RAM</li>
<li>500MB disk space</li>
</ul>
</details> -- highlighted text:
<p>Search results for "python": Found in <mark>Python</mark> Tutorial and Advanced <mark>Python</mark> Patterns.</p>.ARIA: When You Don't Need It
<!-- Redundant: <nav> already has role="navigation" -->
<nav role="navigation">...</nav>
<main role="main">...</main>
<aside role="complementary">...</aside>aria-label is still useful for distinguishing multiple instances of the same element:<nav aria-label="Primary">...</nav>
<nav aria-label="Footer">...</nav>Why This Actually Matters
is instantly clearer than