Heading Hierarchy (h1-h6)
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5), axe, lighthouse, wave, and webhint automatically flag level jumps and missing h1, but they cannot judge whether the chosen rank is semantically correct, only structural gaps.
Closest to 'simple parameterised fix' (e3), quick_fix is to renumber tags so levels descend without gaps and move sizing to CSS, a small pattern replacement, though faked headings may need component changes across a few files.
Closest to 'localised tax' (b3), applies_to is web only and headings are scattered across components, so a broken outline assembled from nested components creates a recurring but contained structural tax rather than defining system shape.
Closest to 'serious trap' (t7), the misconception that heading levels are about font size directly contradicts their true purpose of conveying structural rank, so a developer's intuitive choice based on appearance is reliably wrong.
Also Known As
TL;DR
Explanation
HTML heading elements h1 through h6 communicate document structure, not visual size. Screen reader users rely heavily on headings to navigate: NVDA, JAWS, and VoiceOver all let users jump from heading to heading and pull up a list of all headings to scan a page like a table of contents. For this to work, headings must form a meaningful outline. There should be exactly one h1 describing the page's primary subject, followed by h2 for major sections, h3 for subsections, and so on. Levels must not be skipped when descending (an h2 followed directly by an h4 implies a missing section), because the gap suggests structure that is not there. You may jump back up freely (an h4 followed by an h2 starts a new major section). The cardinal sin is choosing a heading level for its default font size rather than its semantic rank, or using styled <div>s and <p>s that look like headings but carry no heading role in the accessibility tree. WCAG 2.1 covers this under Success Criterion 1.3.1 (Info and Relationships, Level A) and 2.4.6 (Headings and Labels, Level AA); the practice of a logical heading order is also reflected in SC 2.4.10 (Section Headings, AAA). Tools like axe and Lighthouse flag skipped levels and missing h1, but they cannot judge whether a heading is semantically appropriate, so manual review with a heading-navigation command is essential. Use CSS to control appearance and reserve heading levels for structure; if you need large text that is not a section heading, style a paragraph or span instead.
Common Misconception
Why It Matters
Common Mistakes
- Skipping a level when descending, such as following an h2 directly with an h4.
- Choosing a heading level for its default font size instead of its semantic rank.
- Using multiple h1 elements or no h1 at all on a page.
- Faking headings with styled <div> or <b> elements that have no heading role.
- Wrapping non-heading text (like a tagline) in a heading tag just to make it large.
Avoid When
- Do not change a heading level purely to match a desired font size when the level is structurally correct; adjust CSS instead.
- Do not introduce extra heading elements to create visual separators that carry no structural meaning.
When To Use
- On every page, to provide a single h1 and a logical, gap-free descending outline of sections and subsections.
- When refactoring components that render headings, to verify the assembled page still produces a valid outline across nested components.
Code Examples
<!-- Levels skipped and sized by appearance -->
<h1>Acme Store</h1>
<h4>Featured Products</h4> <!-- jumps h1 -> h4 -->
<div class="big-text">Sale Items</div> <!-- looks like a heading, isn't one -->
<h2>Customer Reviews</h2>
<!-- Logical outline, size controlled in CSS -->
<h1>Acme Store</h1>
<h2>Featured Products</h2>
<h3>Sale Items</h3>
<h2>Customer Reviews</h2>
<style>
/* Style for appearance, not structure */
h3 { font-size: 1.75rem; }
</style>