This Lighthouse audit fails when your page skips heading levels, for example, an <h1> followed by an <h3> with no <h2> between them. Screen readers expose the heading hierarchy as a document outline; skipped levels break that outline.
TL;DR
- What: Heading levels (h1 → h2 → h3 → h4...) must not skip a level downward.
- Why it matters: Screen reader navigation by heading is broken when levels jump.
- Fix: Use heading tags by semantic level, not by visual size. Style with CSS, not with which tag you pick.
What the audit checks
Lighthouse walks the rendered DOM in source order and inspects every heading (<h1>–<h6>). It flags pages where a heading is more than one level lower than the previous one.
<h1>Page title</h1>
<h3>Subheading</h3> <!-- ❌ skipped h2 -->
Going back up is fine, <h3> followed by <h2> is OK. The audit only fails on downward jumps.
Why it matters
Screen readers expose page structure as a navigable outline. Users press H (or NVDA: 1, 2, 3 keys for specific levels) to jump between sections. When levels are skipped, the outline reads as: "Page title (level 1), Subheading (level 3, level 2 missing)." It implies there's a level 2 they missed, which is confusing.
It also hurts SEO subtly: Google's structured understanding of your page relies in part on the heading outline.
The fix
Use heading levels semantically, not visually. Pick the tag for what the content means, then size it with CSS.
<!-- BEFORE: tag chosen for visual size -->
<h1>Our pricing plans</h1>
<h3>Free tier</h3>
<h3>Pro tier</h3>
<!-- AFTER: semantic hierarchy -->
<h1>Our pricing plans</h1>
<h2>Free tier</h2>
<h2>Pro tier</h2>
If you want <h2> to look smaller than the original <h3>, do that in CSS:
h2 { font-size: 1.5rem; font-weight: 600; }
Common scenarios
Scenario: Card grids inside a section
<section>
<h2>Features</h2> <!-- correct level for the section -->
<article>
<h3>Real-time sync</h3> <!-- h3 because it's nested in h2's section -->
<p>...</p>
</article>
<article>
<h3>Offline mode</h3> <!-- also h3, sibling article -->
<p>...</p>
</article>
</section>
Scenario: Sidebar with its own headings
The page's main <main> outline doesn't include <aside> content. You can restart heading levels inside an <aside> if you want, but most accessibility experts recommend continuing the document hierarchy.
Scenario: Component libraries (e.g. design systems)
If your design system exports a <Card> component that hard-codes <h3> internally, you'll break heading order whenever you use it inside a section that doesn't have an h2. Solution: make the heading level a prop.
<Card heading="h2" title="Feature name" />
Pitfalls to avoid
- Don't have more than one
<h1>. HTML5 technically allows it via sectioning, but Lighthouse and screen readers expect one h1 per page. - Don't use
<h1>for branding/logo. That's what the<header>element + alt text is for. - Don't pick a heading tag because of its default size. Use CSS for sizing.
Verification
- Re-run Lighthouse. The
heading-orderaudit should pass. - View the document outline with a screen reader's heading list (VoiceOver: VO+U → Headings; NVDA: NVDA+F7).
- Use a browser extension like "Headings Map" or axe DevTools to visualize the heading tree.
Related audits
- Document does not have a main landmark, landmark structure
- Image alt attributes, screen reader content
- Meta description, SEO
Audit your URL at https://lighthouse-md.com.
Audit your page now
Paste your URL, get scores plus a CLAUDE.md plan for Claude Code.