RatedWithAI

RatedWithAI

Accessibility scanner

GuidesSeptember 18, 2026

Your Page Has Two Outlines. A Screen Reader Only Reads One of Them.

The outline you see is font size and weight. The outline a screen reader sees is the h1 to h6 markup, and nothing else. When the two disagree there is no visual symptom at all, which is why broken heading structure survives every design review a page ever gets.

1st
Headings are the most common way screen-reader users find their way around a page
2 SCs
1.3.1 and 2.4.6 are where heading failures live in WCAG 2.1 AA
0
WCAG criteria that forbid skipping a level. That one is advice, not a rule

How a Screen-Reader User Actually Reads Your Page

Almost nobody listens to a web page from the top. A sighted reader skims by scanning big, bold text; a screen-reader user does the same thing by pulling up a list of every heading on the page and jumping between them. In NVDA and JAWS that is the H key and the elements list, and in VoiceOver it is the rotor. WebAIM's recurring screen-reader user survey has found for years that navigating by headings is the most common way people find information on a long page.

That list is built from markup. It contains every h1 through h6, and every element with role="heading" and an aria-level, in document order, with its level. It does not contain a div in 28px bold, a p with a heading class, or a styled span. If your design system renders section titles as styled paragraphs, those sections simply do not exist in the list the reader navigates by.

The opposite failure is just as common and harder to spot: markup used for its size. An h4 chosen because it had the right font size for a product card, an h2 wrapped around a promotional banner, a footer full of h5 elements. Each of those becomes a stop in the heading list with no content section under it.

What WCAG Actually Requires

Two success criteria at levels A and AA cover headings, and neither of them says what most checklists claim it says.

CriterionLevelWhat it requires of headings
1.3.1 Info and RelationshipsAStructure conveyed visually must be available programmatically. Text that looks like a heading must be marked up as one, and markup that says heading must actually be one.
2.4.6 Headings and LabelsAAHeadings that exist must describe the topic or purpose of what follows. It does not require headings to exist.
2.4.1 Bypass BlocksAA way to skip repeated blocks. A heading structure is one of the accepted ways to meet it, alongside skip links and landmarks.
2.4.10 Section HeadingsAAASections are organised with headings. This is the only criterion that asks for headings as such, and almost nobody is measured against AAA.

So the testable failures are narrow: a heading with no text in it, a heading that is an image with no alternative text, a role="heading" with no level, and visible headings that are not marked up. Those fail 1.3.1 or 2.4.6 outright.

Everything else people say about headings is a sufficient technique or a best practice. That matters, because a tool that puts "skipped heading level" into a violation count is inflating it against a rule that does not exist.

The Rules That Are Only Advice (And Still Worth Following)

  • One h1 per page. HTML has never required this, and WCAG does not either. But a page whose first heading is the site logo, or which has four h1 elements, gives the reader no way to jump to the start of the content. Treat more than one h1 as something to review, not something to fail.
  • Do not skip levels. Going from h2 to h4 fails no criterion. It does tell a screen-reader user that there is a missing level-3 section they cannot find, and it is almost always a sign that a heading was picked for its font size. Fix it in the CSS, not by moving the content.
  • Headings should be short. A 40-word heading is read out in full every time a user moves through the list. There is no WCAG limit, but a heading that is really a paragraph defeats the purpose of skimming.
  • Do not hide headings from assistive technology. A heading with aria-hidden="true", or inside a hidden container, can still appear visually while being gone from the list, or the other way around. Either way the two outlines disagree.

The Four Patterns That Break Most Real Sites

The design-system card. A product or article card component renders its title as an h3 because that was the font size in the mockup. Put twenty cards on a listing page and the heading list becomes twenty h3 elements under an h1, with no h2, sitting in the middle of the outline wherever the grid lands.

The page-builder section title. Visual builders often let editors pick "Heading 2" from a style dropdown that only changes the font. The editor sees a heading; the markup is a paragraph. This is a 1.3.1 failure and it is invisible to everyone who uses the page with their eyes.

The icon heading. A section title that is an SVG or an image, with no text alternative, produces a heading that announces as blank. Screen readers will read "heading level 2" and nothing else.

The empty heading. Headings left in templates for spacing, or ones whose text is injected later by JavaScript that fails, are real headings with no name. They show up in the list as a stop that goes nowhere.

<!-- Looks like a heading, is not one: fails 1.3.1 -->
<p class="text-2xl font-bold">Pricing</p>

<!-- Is a heading, announces nothing: fails 1.3.1 / 2.4.6 -->
<h2><svg class="icon-pricing"></svg></h2>

<!-- Fixed: real heading, real name -->
<h2>Pricing</h2>
<h2><svg aria-hidden="true" class="icon-pricing"></svg> Pricing</h2>

<!-- Card titles: pick the level from the outline, the size from CSS -->
<h2>Latest guides</h2>
<article><h3 class="text-base">Heading structure</h3></article>

How to Check Your Own Page

The checker at the top of this article reads the HTML your page serves and lists its outline the way a screen reader will: every heading with its level, in order. Empty headings and image headings with no alt are counted as failures; a missing h1, a second h1 and a skipped level are listed for review and never counted against you, for the reasons above.

Two limits to know. It reads the served HTML, so headings that a single-page app builds in the browser after load will not appear in it. And it is one page. Heading problems almost always come from a shared template or component, so the one page you check is usually telling you about every page that uses the same layout.

That is what the whole-site scan is for. It renders every page the way a browser does, so it sees headings JavaScript builds, and it names every WCAG 2.1 AA violation by criterion with the failing element on the page it is on. The checker's result hands your domain straight to it.

A Five-Minute Manual Check

  • Turn on VoiceOver (Cmd+F5 on a Mac) or NVDA on Windows and open the headings list: the rotor in VoiceOver, Insert+F7 in NVDA.
  • Read the list alone, without looking at the page. Can you tell what the page is about and where its main content starts?
  • Look for entries that are not really sections: logos, promotional banners, card titles repeated twenty times, "Follow us" in the footer.
  • Now look at the page and find big, bold text that did not appear in the list. Each one is a 1.3.1 failure.
  • Check the levels. A jump from h2 to h4 will not fail an audit, but it is usually the fastest way to find a component that chose its heading level for its font size.

Frequently Asked Questions

Is it a WCAG failure to have more than one h1?

No. Neither HTML nor WCAG 2.1 requires a single h1, and multiple h1 elements do not fail any success criterion. It is still worth reviewing, because a page with several h1 elements, or whose only h1 is the logo, gives a screen-reader user no clear way to jump to the start of the main content. Most accessibility teams keep one h1 per page describing the page's main topic as a convention rather than a requirement.

Do skipped heading levels fail WCAG?

No criterion at level A or AA says headings must not skip a level. Using heading levels in order is a sufficient technique for 1.3.1, not a requirement of it. A skip is still a useful signal: it tells a screen-reader user a section is missing, and it usually means a heading was chosen for its font size. Fix it with CSS rather than by restructuring content, and do not treat it as a counted violation.

What is the difference between SC 1.3.1 and SC 2.4.6 for headings?

1.3.1 Info and Relationships (level A) is about markup matching appearance: text that looks like a heading must be one, and markup that says heading must actually head a section. 2.4.6 Headings and Labels (level AA) is about wording: headings that exist must describe the content that follows. A page can pass one and fail the other, for example correct h2 markup around the text 'Section 3'.

Does bold text count as a heading for accessibility?

No. Screen readers build their heading list from h1 to h6 elements and from elements with role='heading' and an aria-level. Bold, large or coloured text is invisible to that list regardless of how it looks. If the text visually introduces a section, mark it up as a heading; if it is just emphasis inside a paragraph, it should not be a heading at all.

Can a heading checker see headings added by JavaScript?

Only if it renders the page. A checker that reads served HTML, like the one on this page, sees what the server sends before any script runs, so a single-page app that builds its headings in the browser can look empty to it. A rendering scanner, such as the whole-site scan, loads each page in a real browser first and sees the final outline a screen reader will read.

Are headings enough to meet the Bypass Blocks requirement?

Usually, yes. SC 2.4.1 Bypass Blocks at level A needs a mechanism to skip repeated content such as navigation, and a proper heading structure is one of the accepted techniques, along with skip links and ARIA landmarks. Many sites use all three. A skip link helps keyboard users who are not using a screen reader, which headings alone do not.

One Page Tells You About the Template

Heading structure breaks in components, not in pages: the card, the builder section, the footer. Check one page with the tool at the top of this article and you have usually found the pattern that every page built from that template shares.

The whole-site scan renders every page, reads the outline JavaScript builds, and names each WCAG 2.1 AA failure with the element and page it is on. No signup, no card.

Open the heading structure checker on its own page →