HTMLhighsemantics
Use semantic HTML elements
rule · html5-semantic-elements
HTML5 semantic elements provide meaningful structure to web content, improving accessibility, SEO, and code maintainability.
Code Example
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Semantic HTML Example</title>
</head>
<body>
<header>
<h1>Site Title</h1>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
</nav>
</header>
<main>
<article>
<header>
<h1>Article Title</h1>
<time datetime="2024-01-15">January 15, 2024</time>
</header>
<section>
<h2>Section Heading</h2>
<p>Content goes here...</p>
</section>
<aside>
<h3>Related Links</h3>
<ul>
<li><a href="/related">Related Article</a></li>
</ul>
</aside>
</article>
</main>
<footer>
<p>© 2024 Company Name</p>
</footer>
</body>
</html>Why It Matters
Screen readers use semantic elements to navigate pages—users can jump directly to <main> content or <nav>. Search engines also use semantics to understand content hierarchy.
Semantic Elements Reference
Document Structure
HTML
<!-- Page header with site branding and navigation -->
<header>
<h1>Site Logo</h1>
<nav aria-label="Main navigation">
<ul><!-- navigation items --></ul>
</nav>
</header>
<!-- Main content area -->
<main>
<!-- Primary content goes here -->
</main>
<!-- Page footer with site info -->
<footer>
<p>Copyright information</p>
<nav aria-label="Footer navigation">
<ul><!-- footer links --></ul>
</nav>
</footer>Content Grouping
HTML
<!-- Self-contained content -->
<article>
<h2>Blog Post Title</h2>
<p>Post content...</p>
</article>
<!-- Thematic content grouping -->
<section>
<h2>Products</h2>
<div>Product listings...</div>
</section>
<!-- Sidebar or tangentially related content -->
<aside>
<h3>Advertisement</h3>
<p>Ad content...</p>
</aside>Framework Examples
Next.js with Semantic Structure
JSX
// components/Layout.js
export default function Layout({ children }) {
return (
<html lang="en">
<body>
<header className="site-header">
<h1>My Website</h1>
<nav aria-label="Main navigation">
<ul>
<li><Link href="/">Home</Link></li>
<li><Link href="/about">About</Link></li>
<li><Link href="/blog">Blog</Link></li>
</ul>
</nav>
</header>
<main className="main-content">
{children}
</main>
<footer className="site-footer">
<p>© 2024 My Website</p>
</footer>
</body>
</html>
)
}
// pages/blog/[slug].js
export default function BlogPost({ post }) {
return (
<article>
<header>
<h1>{post.title}</h1>
<time dateTime={post.publishedAt}>
{formatDate(post.publishedAt)}
</time>
<address>
By <a href={`/authors/${post.author.slug}`}>
{post.author.name}
</a>
</address>
</header>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
<aside>
<h2>Related Posts</h2>
<ul>
{post.relatedPosts.map(related => (
<li key={related.id}>
<Link href={`/blog/${related.slug}`}>
{related.title}
</Link>
</li>
))}
</ul>
</aside>
</article>
)
}React Component Structure
JSX
// BlogLayout.jsx
function BlogLayout({ children }) {
return (
<div className="blog-layout">
<header className="blog-header">
<h1>My Blog</h1>
<nav aria-label="Blog categories">
<ul>
<li><a href="/tech">Tech</a></li>
<li><a href="/design">Design</a></li>
<li><a href="/business">Business</a></li>
</ul>
</nav>
</header>
<main className="blog-main">
{children}
</main>
<aside className="blog-sidebar">
<section>
<h2>Recent Posts</h2>
<RecentPosts />
</section>
<section>
<h2>Categories</h2>
<CategoryList />
</section>
</aside>
</div>
)
}
// ArticleCard.jsx
function ArticleCard({ article }) {
return (
<article className="article-card">
<header>
<h3>
<a href={`/articles/${article.slug}`}>
{article.title}
</a>
</h3>
<time dateTime={article.publishedAt}>
{article.publishedDate}
</time>
</header>
<p>{article.excerpt}</p>
<footer>
<a href={`/articles/${article.slug}`}>
Read more
</a>
</footer>
</article>
)
}Vue.js Semantic Templates
VUE
<!-- BlogPost.vue -->
<template>
<article class="blog-post">
<header class="post-header">
<h1>{{ post.title }}</h1>
<div class="post-meta">
<time :datetime="post.publishedAt">
{{ formatDate(post.publishedAt) }}
</time>
<address>
By <router-link :to="`/authors/${post.author.slug}`">
{{ post.author.name }}
</router-link>
</address>
</div>
</header>
<div class="post-content" v-html="post.content"></div>
<footer class="post-footer">
<nav aria-label="Post navigation">
<router-link v-if="previousPost" :to="previousPost.url">
← {{ previousPost.title }}
</router-link>
<router-link v-if="nextPost" :to="nextPost.url">
{{ nextPost.title }} →
</router-link>
</nav>
</footer>
</article>
</template>
<!-- HomePage.vue -->
<template>
<div class="homepage">
<header class="hero">
<h1>Welcome to My Website</h1>
<p>Building amazing web experiences</p>
</header>
<main class="homepage-content">
<section class="featured-posts">
<h2>Featured Articles</h2>
<div class="post-grid">
<article v-for="post in featuredPosts" :key="post.id">
<h3>{{ post.title }}</h3>
<p>{{ post.excerpt }}</p>
</article>
</div>
</section>
<section class="services">
<h2>Our Services</h2>
<div class="service-list">
<div v-for="service in services" :key="service.id">
<h3>{{ service.name }}</h3>
<p>{{ service.description }}</p>
</div>
</div>
</section>
</main>
<aside class="sidebar">
<section class="newsletter">
<h2>Newsletter</h2>
<NewsletterForm />
</section>
</aside>
</div>
</template>Complex Content Structures
E-commerce Product Page
HTML
<main class="product-page">
<article class="product">
<header>
<h1>Product Name</h1>
<p class="price">$99.99</p>
</header>
<section class="product-images">
<figure>
<img src="product.jpg" alt="Product photo">
<figcaption>Main product image</figcaption>
</figure>
</section>
<section class="product-details">
<h2>Description</h2>
<p>Product description...</p>
</section>
<section class="product-reviews">
<h2>Customer Reviews</h2>
<article class="review">
<header>
<h3>Great product!</h3>
<div class="rating" aria-label="5 out of 5 stars">★★★★★</div>
</header>
<p>Review content...</p>
<footer>
<address>By John Doe</address>
<time datetime="2024-01-10">January 10, 2024</time>
</footer>
</article>
</section>
<aside class="related-products">
<h2>You Might Also Like</h2>
<!-- Related products -->
</aside>
</article>
</main>News Website Structure
HTML
<header class="site-header">
<h1>News Site</h1>
<nav aria-label="Main navigation">
<ul>
<li><a href="/politics">Politics</a></li>
<li><a href="/sports">Sports</a></li>
<li><a href="/tech">Technology</a></li>
</ul>
</nav>
</header>
<main class="news-main">
<section class="breaking-news">
<h2>Breaking News</h2>
<article class="featured-story">
<header>
<h3>Major News Story</h3>
<time datetime="2024-01-15T14:30:00Z">
January 15, 2024 at 2:30 PM
</time>
</header>
<p>Story summary...</p>
</article>
</section>
<section class="latest-news">
<h2>Latest News</h2>
<div class="news-grid">
<article class="news-item">
<h3><a href="/news/story-1">Story Title</a></h3>
<p>Story excerpt...</p>
<footer>
<time datetime="2024-01-15">Jan 15</time>
</footer>
</article>
</div>
</section>
</main>
<aside class="sidebar">
<section class="trending">
<h2>Trending</h2>
<ol>
<li><a href="/trending/1">Trending Story 1</a></li>
<li><a href="/trending/2">Trending Story 2</a></li>
</ol>
</section>
</aside>Accessibility Benefits
Screen Reader Navigation
HTML
<!-- Provides landmarks for screen readers -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<!-- Skip to main content link -->
<a href="#main" class="skip-link">Skip to main content</a>
<main id="main" tabindex="-1">
<!-- Main content -->
</main>Heading Hierarchy
HTML
<article>
<h1>Main Article Title</h1> <!-- Level 1 -->
<section>
<h2>Section Title</h2> <!-- Level 2 -->
<h3>Subsection Title</h3> <!-- Level 3 -->
<p>Content...</p>
<h3>Another Subsection</h3> <!-- Level 3 -->
<p>More content...</p>
</section>
<section>
<h2>Another Section</h2> <!-- Level 2 -->
<p>Section content...</p>
</section>
</article>SEO Benefits
Rich Snippets Support
HTML
<article itemscope itemtype="http://schema.org/Article">
<header>
<h1 itemprop="headline">Article Title</h1>
<time itemprop="datePublished" datetime="2024-01-15">
January 15, 2024
</time>
<address itemprop="author" itemscope itemtype="http://schema.org/Person">
By <span itemprop="name">Author Name</span>
</address>
</header>
<div itemprop="articleBody">
<p>Article content...</p>
</div>
</article>Common Anti-Patterns
❌ Div Soup (Non-semantic)
HTML
<div class="header">
<div class="title">Site Title</div>
<div class="navigation">
<div class="nav-item">Home</div>
<div class="nav-item">About</div>
</div>
</div>
<div class="content">
<div class="article">
<div class="article-title">Article Title</div>
<div class="article-content">Content...</div>
</div>
</div>
<div class="footer">Footer content</div>✅ Semantic Alternative
HTML
<header>
<h1>Site Title</h1>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>Article Title</h1>
<p>Content...</p>
</article>
</main>
<footer>Footer content</footer>Tools & Validation
- HTML5 Outliner: Visualize document structure
- WAVE: Check semantic structure accessibility
- axe DevTools: Accessibility testing including landmarks
- Lighthouse: SEO and accessibility audit
- W3C Markup Validator: Validate HTML5 semantic usage
Browser Support
All modern browsers fully support HTML5 semantic elements. For older browsers (IE8 and below), you can use the HTML5 shiv:
HTML
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<![endif]-->Verification
Automated Checks
- Inspect the final rendered HTML in the browser or page source to confirm the rule is satisfied.
- Validate the affected markup with browser tooling or an HTML validator where appropriate.
- Test one representative route or template that uses the pattern.
- Re-check shared components that emit the same markup so the fix is consistent.
Manual Checks
- Verify the rendered browser behavior manually on representative routes and supported browsers so the user-facing outcome matches the rule.