Back to Blog
HTMLSemanticAccessibilityBest Practices

Semantic HTML Elements Guide

Use semantic HTML correctly. From document structure to ARIA to accessibility best practices.

B
Bootspring Team
Engineering
June 5, 2021
5 min read

Semantic HTML improves accessibility and SEO. Here's how to use elements correctly.

Document Structure#

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Page Title</title> 7</head> 8<body> 9 <header> 10 <nav aria-label="Main navigation"> 11 <!-- Navigation --> 12 </nav> 13 </header> 14 15 <main> 16 <article> 17 <!-- Main content --> 18 </article> 19 </main> 20 21 <aside> 22 <!-- Sidebar content --> 23 </aside> 24 25 <footer> 26 <!-- Footer content --> 27 </footer> 28</body> 29</html>

Header and Navigation#

1<!-- Site header --> 2<header> 3 <a href="/" aria-label="Homepage"> 4 <img src="/logo.svg" alt="Company Name"> 5 </a> 6 7 <nav aria-label="Main navigation"> 8 <ul> 9 <li><a href="/" aria-current="page">Home</a></li> 10 <li><a href="/about">About</a></li> 11 <li><a href="/products">Products</a></li> 12 <li><a href="/contact">Contact</a></li> 13 </ul> 14 </nav> 15 16 <nav aria-label="User menu"> 17 <ul> 18 <li><a href="/account">Account</a></li> 19 <li><a href="/logout">Logout</a></li> 20 </ul> 21 </nav> 22</header> 23 24<!-- Breadcrumb navigation --> 25<nav aria-label="Breadcrumb"> 26 <ol> 27 <li><a href="/">Home</a></li> 28 <li><a href="/products">Products</a></li> 29 <li><a href="/products/shoes" aria-current="page">Shoes</a></li> 30 </ol> 31</nav>

Main Content#

1<main> 2 <!-- Article for self-contained content --> 3 <article> 4 <header> 5 <h1>Article Title</h1> 6 <p> 7 By <a href="/author/john">John Doe</a> 8 on <time datetime="2024-01-15">January 15, 2024</time> 9 </p> 10 </header> 11 12 <section> 13 <h2>Introduction</h2> 14 <p>Article introduction...</p> 15 </section> 16 17 <section> 18 <h2>Main Points</h2> 19 <p>Content...</p> 20 21 <figure> 22 <img src="/chart.png" alt="Sales growth chart showing 50% increase"> 23 <figcaption>Figure 1: Q4 Sales Growth</figcaption> 24 </figure> 25 </section> 26 27 <footer> 28 <p>Tags: 29 <a href="/tags/tech" rel="tag">Technology</a>, 30 <a href="/tags/business" rel="tag">Business</a> 31 </p> 32 </footer> 33 </article> 34 35 <!-- Related articles --> 36 <aside> 37 <h2>Related Articles</h2> 38 <ul> 39 <li><a href="/article-1">Related Article 1</a></li> 40 <li><a href="/article-2">Related Article 2</a></li> 41 </ul> 42 </aside> 43</main>

Sections and Headings#

1<!-- Section for thematic grouping --> 2<section aria-labelledby="features-heading"> 3 <h2 id="features-heading">Features</h2> 4 5 <article> 6 <h3>Feature One</h3> 7 <p>Description...</p> 8 </article> 9 10 <article> 11 <h3>Feature Two</h3> 12 <p>Description...</p> 13 </article> 14</section> 15 16<!-- Heading hierarchy (always in order) --> 17<h1>Page Title</h1> 18 <h2>Section</h2> 19 <h3>Subsection</h3> 20 <h4>Sub-subsection</h4> 21 <h3>Another Subsection</h3> 22 <h2>Another Section</h2> 23 24<!-- Don't skip heading levels --> 25<!-- Bad: h1 -> h3 (skipping h2) --> 26<!-- Good: h1 -> h2 -> h3 -->

Lists#

1<!-- Unordered list (no sequence) --> 2<ul> 3 <li>Feature one</li> 4 <li>Feature two</li> 5 <li>Feature three</li> 6</ul> 7 8<!-- Ordered list (sequence matters) --> 9<ol> 10 <li>Step one</li> 11 <li>Step two</li> 12 <li>Step three</li> 13</ol> 14 15<!-- Description list (key-value pairs) --> 16<dl> 17 <dt>HTML</dt> 18 <dd>HyperText Markup Language</dd> 19 20 <dt>CSS</dt> 21 <dd>Cascading Style Sheets</dd> 22 23 <dt>JS</dt> 24 <dd>JavaScript</dd> 25</dl> 26 27<!-- Nested lists --> 28<ul> 29 <li> 30 Category One 31 <ul> 32 <li>Item 1.1</li> 33 <li>Item 1.2</li> 34 </ul> 35 </li> 36 <li>Category Two</li> 37</ul>

Tables#

1<table> 2 <caption>Monthly Sales Report</caption> 3 4 <thead> 5 <tr> 6 <th scope="col">Month</th> 7 <th scope="col">Sales</th> 8 <th scope="col">Growth</th> 9 </tr> 10 </thead> 11 12 <tbody> 13 <tr> 14 <th scope="row">January</th> 15 <td>$10,000</td> 16 <td>+5%</td> 17 </tr> 18 <tr> 19 <th scope="row">February</th> 20 <td>$12,000</td> 21 <td>+20%</td> 22 </tr> 23 </tbody> 24 25 <tfoot> 26 <tr> 27 <th scope="row">Total</th> 28 <td>$22,000</td> 29 <td>+12.5%</td> 30 </tr> 31 </tfoot> 32</table> 33 34<!-- Complex table with colspan/rowspan --> 35<table> 36 <thead> 37 <tr> 38 <th rowspan="2">Name</th> 39 <th colspan="2">Scores</th> 40 </tr> 41 <tr> 42 <th>Math</th> 43 <th>Science</th> 44 </tr> 45 </thead> 46 <tbody> 47 <tr> 48 <td>Alice</td> 49 <td>95</td> 50 <td>88</td> 51 </tr> 52 </tbody> 53</table>

Forms#

1<form action="/submit" method="post"> 2 <fieldset> 3 <legend>Personal Information</legend> 4 5 <div> 6 <label for="name">Full Name</label> 7 <input 8 type="text" 9 id="name" 10 name="name" 11 required 12 autocomplete="name" 13 > 14 </div> 15 16 <div> 17 <label for="email">Email</label> 18 <input 19 type="email" 20 id="email" 21 name="email" 22 required 23 autocomplete="email" 24 aria-describedby="email-hint" 25 > 26 <small id="email-hint">We'll never share your email</small> 27 </div> 28 </fieldset> 29 30 <fieldset> 31 <legend>Preferences</legend> 32 33 <div> 34 <input type="checkbox" id="newsletter" name="newsletter"> 35 <label for="newsletter">Subscribe to newsletter</label> 36 </div> 37 38 <div> 39 <span id="contact-label">Preferred contact method</span> 40 <div role="group" aria-labelledby="contact-label"> 41 <input type="radio" id="contact-email" name="contact" value="email"> 42 <label for="contact-email">Email</label> 43 44 <input type="radio" id="contact-phone" name="contact" value="phone"> 45 <label for="contact-phone">Phone</label> 46 </div> 47 </div> 48 </fieldset> 49 50 <button type="submit">Submit</button> 51</form>

Interactive Elements#

1<!-- Details/Summary (native accordion) --> 2<details> 3 <summary>Click to expand</summary> 4 <p>Hidden content that appears when expanded.</p> 5</details> 6 7<!-- Dialog (modal) --> 8<dialog id="my-dialog"> 9 <h2>Dialog Title</h2> 10 <p>Dialog content...</p> 11 <form method="dialog"> 12 <button>Close</button> 13 </form> 14</dialog> 15 16<button onclick="document.getElementById('my-dialog').showModal()"> 17 Open Dialog 18</button> 19 20<!-- Progress --> 21<label for="progress">Upload progress:</label> 22<progress id="progress" value="70" max="100">70%</progress> 23 24<!-- Meter --> 25<label for="fuel">Fuel level:</label> 26<meter id="fuel" value="0.6" min="0" max="1" low="0.25" high="0.75" optimum="1"> 27 60% 28</meter>

Time and Data#

1<!-- Time element --> 2<p>Published on <time datetime="2024-01-15">January 15, 2024</time></p> 3 4<p>Event starts at <time datetime="14:30">2:30 PM</time></p> 5 6<p> 7 <time datetime="2024-06-01T09:00:00-05:00"> 8 June 1, 2024 at 9:00 AM EST 9 </time> 10</p> 11 12<!-- Duration --> 13<p>Duration: <time datetime="PT2H30M">2 hours 30 minutes</time></p> 14 15<!-- Data element --> 16<p>Product: <data value="12345">Widget Pro</data></p> 17 18<!-- Address element (contact info) --> 19<address> 20 <p>Contact us:</p> 21 <a href="mailto:info@example.com">info@example.com</a> 22 <a href="tel:+1234567890">+1 (234) 567-890</a> 23</address>

Inline Semantics#

1<!-- Strong (important) vs Bold (visual) --> 2<p><strong>Warning:</strong> This action cannot be undone.</p> 3<p>The <b>quick</b> brown fox.</p> 4 5<!-- Emphasis vs Italic --> 6<p>You <em>must</em> complete this form.</p> 7<p>The <i>USS Enterprise</i> is a famous ship.</p> 8 9<!-- Other inline elements --> 10<p>Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy.</p> 11 12<p>The function returns <code>undefined</code>.</p> 13 14<p><samp>Error: File not found</samp></p> 15 16<p>The variable <var>x</var> equals 10.</p> 17 18<p><abbr title="HyperText Markup Language">HTML</abbr> is great.</p> 19 20<p>The price is <del>$100</del> <ins>$75</ins>.</p> 21 22<p>Water is H<sub>2</sub>O. E = mc<sup>2</sup>.</p> 23 24<p><mark>Highlighted text</mark> stands out.</p> 25 26<p><q>To be or not to be</q>, Shakespeare wrote.</p> 27 28<blockquote cite="https://example.com"> 29 <p>A longer quotation that spans multiple lines.</p> 30</blockquote>

Best Practices#

Structure: ✓ Use one h1 per page ✓ Maintain heading hierarchy ✓ Use landmarks (header, main, nav, footer) ✓ Use article for self-contained content Accessibility: ✓ Add alt text to images ✓ Use labels for form inputs ✓ Provide skip links ✓ Use ARIA when needed SEO: ✓ Use descriptive headings ✓ Use semantic elements correctly ✓ Add meta descriptions ✓ Use structured data

Conclusion#

Semantic HTML provides meaning to content, improving accessibility and SEO. Use appropriate elements for their intended purpose—headings for structure, articles for content, and forms with proper labels. This creates better experiences for all users and search engines.

Share this article

Help spread the word about Bootspring