Lighthouse audit heading-order · Accessibility

Heading elements not in sequentially-descending order: how to fix it

View raw .md for LLMs / your notes
Quick answer: This audit fails when headings skip a level, such as an h1 followed directly by an h3. Fix it by choosing heading tags by document hierarchy rather than visual size, using exactly one h1, never skipping a level downward, and styling text size with CSS instead.

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 does the heading-order audit check?

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 does heading order matter?

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.

How do I fix heading order?

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; }

What are common heading-order 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" />

What heading-order pitfalls should I avoid?

How do I verify heading order?

  1. Re-run Lighthouse. The heading-order audit should pass.
  2. View the document outline with a screen reader's heading list (VoiceOver: VO+U → Headings; NVDA: NVDA+F7).
  3. Use a browser extension like "Headings Map" or axe DevTools to visualize the heading tree.

Related audits


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.

Run audit →