Heading order: why skipping from h1 to h3 matters
Screen reader users navigate by heading level, and a skipped level makes the outline harder to follow. squirrel checks document order on every page.
What heading order is
Heading levels are an outline, not a type scale. A screen reader user pressing 2 moves between second-level headings and expects everything under one of them to belong to it. Skipping from <h1> to <h3> implies a missing section, and the user has to guess whether they missed something.
Going back up a level is not a skip. An <h3> followed by an <h2> closes one section and opens the next.
What squirrel checks
One check, heading-order, at severity warning. It reads every <h1> through <h6> in document order and compares each level with the one before it.
- Warn when a heading is more than one level deeper than its predecessor. Report message:
N heading level skip(s) detected. Every skip is listed, asH3 after H1. - Pass with
Heading levels follow correct order. - Info with
No headings found.
The first heading on a page is never counted as a skip, whatever its level, so a page that starts at <h3> passes this check. Whether the page has a top-level heading at all is core/h1.
How to fix it
<h1>Pricing</h1>
<h2>Plans</h2>
<h3>Team</h3>
<h2>Frequently asked questions</h2>Pick the level from the position in the outline and set the size in CSS. If an <h3> looks right because you want smaller text, style the <h2> instead.
Two independent components stacked on a page are the usual source. Each renders a sensible internal outline, and the combination skips a level at the seam. Passing the starting level into the component as a prop solves it.
| Rule ID | a11y/heading-order |
| Category | Accessibility |
| Scope | Per-page |
| Severity | warning |
| Weight | 4/10 |
Enable / disable
Disable this rule
[rules]
disable = ["a11y/heading-order"]Disable all Accessibility rules
[rules]
disable = ["a11y/*"]Enable only this rule
[rules]
enable = ["a11y/heading-order"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- content/heading-hierarchy: the same outline judged for structure and SEO.
- a11y/empty-heading: headings in the outline with nothing to announce.
- core/h1: whether the page has an
<h1>, and only one of them. - a11y/landmark-regions: the other structure screen readers navigate by.
Accessibility findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.
References
- The heading elements, MDN
- Understanding SC 1.3.1 Info and Relationships, W3C
- G141: Organizing a page using headings, W3C
Check your site
Run squirrel audit https://example.com and open the Accessibility section of the report. Each skip is listed with the level that jumped and the level before it. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.