View contents
Semantic HTML: Building Meaningful Document Structure
Introduction
Semantic HTML means using HTML elements according to their intended purpose rather than their visual appearance. WCAG 1.3.1 (Info and Relationships) requires that information, structure, and relationships conveyed through presentation can be programmatically determined. Using semantic HTML is the foundation of accessible web development.
When developers use <div> and <span> for everything, assistive technologies cannot understand the page structure. Screen reader users lose the ability to navigate by headings, landmarks, or lists—features that make web content navigable and comprehensible.
What Is Semantic HTML?
The Basic Concept
Semantic elements describe their meaning to both browsers and developers:
<!-- Non-semantic: Meaning unclear -->
<div class="header">
<div class="nav">
<div class="nav-item">Home</div>
</div>
</div>
<div class="main">
<div class="big-text">Welcome</div>
</div>
<!-- Semantic: Meaning is clear -->
<header>
<nav>
<a href="/">Home</a>
</nav>
</header>
<main>
<h1>Welcome</h1>
</main>
Who Benefits
| User Type | Benefit |
|---|---|
| Screen reader users | Navigate by headings, landmarks, and lists |
| Keyboard users | Understand page regions and structure |
| Search engines | Better understand content and relevance |
| Developers | Code is self-documenting and maintainable |
| All users | Consistent, predictable page behavior |
WCAG Requirements
1.3.1 Info and Relationships (Level A)
Information, structure, and relationships conveyed through presentation can be programmatically determined or are available in text.
This means:
- Visual headings should use heading elements (
<h1>-<h6>) - Visual lists should use list elements (
<ul>,<ol>,<dl>) - Data tables should use proper table markup
- Form relationships should be explicit
4.1.2 Name, Role, Value (Level A)
For all user interface components, the name and role can be programmatically determined.
This means:
- Native HTML elements have built-in roles
- Custom components need ARIA when necessary
- Interactive elements are properly identified
Key Semantic Elements
Document Structure
<!DOCTYPE html>
<html lang="en">
<head>
<title>Page Title</title>
</head>
<body>
<header>
<!-- Site header, logo, main navigation -->
</header>
<nav aria-label="Main navigation">
<!-- Primary navigation links -->
</nav>
<main>
<!-- Primary page content (only one per page) -->
</main>
<aside>
<!-- Complementary content (sidebar) -->
</aside>
<footer>
<!-- Site footer, copyright, secondary links -->
</footer>
</body>
</html>
Content Sections
| Element | Purpose | Use When |
|---|---|---|
<article> |
Self-contained content | Blog posts, news articles, comments |
<section> |
Thematic grouping | Chapters, tabbed content |
<aside> |
Related but separate | Sidebars, pull quotes |
<nav> |
Navigation links | Main nav, breadcrumbs, TOC |
<header> |
Introductory content | Page header, article header |
<footer> |
Footer content | Copyright, related links |
Heading Hierarchy
<!-- Proper heading hierarchy -->
<h1>Page Title</h1>
<h2>Main Section</h2>
<h3>Subsection</h3>
<h3>Another Subsection</h3>
<h2>Another Main Section</h2>
<h3>Subsection</h3>
<!-- BAD: Skipped heading levels -->
<h1>Page Title</h1>
<h3>Subsection</h3> <!-- Skipped h2! -->
<h5>Deep section</h5> <!-- Skipped h4! -->
Common Semantic HTML Problems
1. Div Soup
<!-- BAD: Everything is a div -->
<div class="header">
<div class="logo">Site Name</div>
<div class="nav">
<div class="nav-item">Home</div>
<div class="nav-item">About</div>
</div>
</div>
<!-- GOOD: Proper semantic elements -->
<header>
<a href="/" class="logo">Site Name</a>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
2. Fake Headings
<!-- BAD: Styled text instead of headings -->
<div class="title">Page Title</div>
<p><strong>Section Heading</strong></p>
<!-- GOOD: Actual heading elements -->
<h1>Page Title</h1>
<h2>Section Heading</h2>
3. Non-Semantic Lists
<!-- BAD: Fake list -->
<div class="list">
<div>• Item one</div>
<div>• Item two</div>
</div>
<!-- GOOD: Proper list -->
<ul>
<li>Item one</li>
<li>Item two</li>
</ul>
4. Buttons That Aren’t Buttons
<!-- BAD: Div acting as button -->
<div class="button" onclick="submit()">Submit</div>
<!-- GOOD: Actual button -->
<button type="submit">Submit</button>
<!-- BAD: Link acting as button -->
<a href="#" onclick="submit(); return false;">Submit</a>
<!-- GOOD: Button for actions, links for navigation -->
<button type="button" onclick="submit()">Submit</button>
Text-Level Semantics
Emphasis and Importance
<!-- Emphasis (stress) -->
<p>I <em>really</em> want to go.</p>
<!-- Strong importance -->
<p><strong>Warning:</strong> This action cannot be undone.</p>
<!-- Both (avoid using for styling) -->
<p><strong><em>Critical alert!</em></strong></p>
Other Text Elements
| Element | Meaning | Example |
|---|---|---|
<abbr> |
Abbreviation | <abbr title="Web Content Accessibility Guidelines">WCAG</abbr> |
<cite> |
Citation/reference | <cite>Web Content Accessibility Guidelines</cite> |
<code> |
Computer code | <code>console.log()</code> |
<time> |
Date/time | <time datetime="2024-12-16">December 16, 2024</time> |
<mark> |
Highlighted text | <mark>search term</mark> |
Testing Semantic Structure
Quick Manual Test
- Disable CSS and view the page
- Is the content still logical and navigable?
- Are headings, lists, and sections visible?
- Can you understand the page structure?
What to Verify
- [ ] Page has logical heading hierarchy (h1 → h2 → h3)
- [ ] Only one
<h1>per page (usually) - [ ] Navigation uses
<nav>element - [ ] Main content is in
<main>element - [ ] Lists use
<ul>,<ol>, or<dl>appropriately - [ ] Buttons use
<button>, links use<a> - [ ] Tables have
<thead>,<tbody>, and proper headers
Tools for Testing
- WAVE - Shows document outline and structure
- HeadingsMap - Browser extension for heading hierarchy
- axe DevTools - Reports semantic structure issues
- Screen reader - Navigate by headings and landmarks
Best Practices Summary
| Do | Don’t |
|---|---|
| Use heading elements for headings | Use styled divs or spans for headings |
| Use nav for navigation | Use divs with class=“nav” |
| Use button for actions | Use divs or spans with click handlers |
| Use semantic HTML first | Start with divs and add ARIA |
| Maintain heading hierarchy | Skip heading levels |
| Use lists for grouped items | Use line breaks for list-like content |
Related Articles
- Semantic HTML Implementation Guide - Detailed patterns
- ARIA Labels Guide - When ARIA is needed
- WCAG Compliance Hub - All accessibility evaluators
References
- W3C - WCAG 2.2 SC 1.3.1 Info and Relationships
- W3C - WCAG 2.2 SC 4.1.2 Name, Role, Value
- MDN - HTML elements reference
- WebAIM - Semantic Structure