sfw/fix
page-has-heading-one medium

Page must contain a level-one heading

The page has no <h1>, so screen-reader users can't jump straight to the main topic and have to wade through the page to orient.

What you see

Page must contain a level-one heading (page-has-heading-one)
Fix any of the following:
  Page must have a level-one heading
  Document does not contain an h1, or it appears after the main content

What’s actually happening

axe (this is a Deque best-practice rule, not a strict WCAG failure) looks for an h1:not([role]) — or an element with role="heading" and aria-level="1" — appearing before the main content, and reports when none exists. Screen-reader users lean on the h1 as the "you are here": pressing 1 in NVDA/JAWS or using the VoiceOver rotor jumps to it to learn the page's subject in one keystroke. With no h1, that shortcut lands nowhere and they're forced to read down from the top to figure out what the page even is. The usual cause is a design that styles a <div> or <p> as the big title instead of marking it up as a real h1, so it looks like a heading and isn't one.

Common causes

  • The page title is a styled <div>/<span>/<p> sized to look like a heading but never marked as <h1>
  • The layout starts at <h2> because someone disliked the h1's default size and reached for a smaller tag
  • A logo or site name occupies the visual title slot and there's no real first-level heading for the page's actual topic
  • A template renders the h1 below the main content (or inside an aside), so it exists but not before the content as the rule expects
  • A single-page app swaps views client-side without rendering an h1 for the new view

How to fix it

  1. Mark the main title as a real <h1>Find the text that names what this page is about and put it in an <h1>. One per page, placed at the start of the main content. If a styled div is already playing that role, change the tag to h1 — the text and meaning stay, the semantics get fixed.
  2. Style the h1 in CSS, don't downgrade the tagIf the h1's default size is too big, size it with CSS (h1{font-size:1.5rem}). Never pick h2 just to get smaller text — the level signals position in the outline, not how large the text should be. Appearance is CSS's job.
  3. Don't let the logo stand in for the headingA header logo isn't the page's h1. Keep the logo as a linked image with alt text, and add a separate h1 naming the page's topic — visible, or visually hidden with an sr-only class if the design truly has no room for it on screen.
  4. Render an h1 per view in single-page appsWhen the route changes and new content mounts, make sure that view includes its own h1 and that it lands before the main content. Move focus to it (or to the region) on navigation so screen-reader users get oriented after the swap.
  5. Verify with the headings listRe-run axe to clear page-has-heading-one, then open the screen reader's headings list (VoiceOver rotor, NVDA elements list). The h1 should sit at the top as the page's title, with h2s nested beneath it — a clean table of contents, no orphan first heading.

Stop it recurring

Bake exactly one <h1> naming the page topic into every page template, and handle all title sizing in CSS so nobody downgrades the tag for looks.

Related errors