Heading elements are among the oldest navigational affordances on the web. Long before nav landmarks, skip links, or ARIA roles, h1 through h6 gave screen reader users a way to scan a page — jumping between headings the way a sighted reader skims bold section titles in a magazine. That model still works. The story of how the HTML5 specification tried to improve on it, failed quietly, and was eventually retracted is worth understanding — because developers were building toward a standard that browsers never shipped.

Why Heading Sequence Matters

Screen readers expose heading level as metadata. When a user navigates by heading — which is the most common page-skimming technique for blind users according to WebAIM’s screen reader surveys — they hear both the heading text and its level. “Heading level 2: Product features.” That numbering is meaningful: it tells users where they are in the document’s hierarchy and how deeply nested the current topic is.

A document that jumps from h1 to h3 without an intervening h2 creates a gap users notice. A document that uses h2 elements scattered without structural intent — labeling sidebars, promo blocks, and body sections all at the same level — flattens the hierarchy into noise. The WCAG success criterion 1.3.1 (Info and Relationships) requires that structure conveyed visually also be available programmatically, and heading level is the primary mechanism for conveying document hierarchy.

The practical rule: heading levels must reflect nesting depth, must not skip levels downward, and must not be chosen for visual size. If you want a visually smaller heading at the same logical level, use CSS — not a lower heading element.

<!-- Correct: h2 follows h1, h3 nested inside h2 topic -->
<h1>Parking Access Control Systems</h1>
  <h2>Barrier Gates</h2>
    <h3>Single-Arm vs. Dual-Arm Configurations</h3>
    <h3>Installation Requirements</h3>
  <h2>License Plate Recognition</h2>
    <h3>Camera Placement</h3>

<!-- Incorrect: level skipped, h4 appears without h2 or h3 context -->
<h1>Parking Access Control Systems</h1>
  <h4>Barrier Gates</h4>

Beyond screen readers, search engines use heading structure to understand topical organization. An h1 signals the primary topic; h2 and h3 elements signal subtopics and their relationships. A well-sequenced heading outline is a signal that the document is organized — which correlates, if loosely, with content quality.

The HTML5 Outline Algorithm: A Standard That Never Shipped

When HTML5 introduced sectioning content elements — article, section, nav, and aside — the specification also introduced a new concept: the document outline algorithm. The premise was elegant. Each sectioning element would create its own independent heading scope. An h1 inside a <section> nested inside another <section> would be treated as a third-level heading in the overall document outline — even though its markup said h1.

This meant, in theory, that authors could use h1 for every section heading, and the browser would infer hierarchy from structural nesting rather than heading number. A self-contained <article> component could begin with its own h1 without disrupting the host page’s outline. Reusable components would compose cleanly.

The algorithm appeared in the HTML5 specification published by the WHATWG and the W3C. It was described in detail. It was taught in web development courses. It was cited as a reason that using multiple h1 elements per page was now acceptable — or even recommended.

The problem: no browser ever implemented it.

Not Chrome. Not Firefox. Not Safari. Not Edge in any of its incarnations. The algorithm existed entirely in specification text, not in any rendering engine. Assistive technologies, which rely on the browser’s accessibility tree rather than parsing the spec themselves, similarly never adopted it. Screen readers continued to expose heading level based on the literal heading element number — h1 through h6 — regardless of how many <section> elements wrapped it.

The gap between spec and implementation persisted for years. Developers who followed the spec and built components with h1 headings inside <section> elements produced documents that looked correct in the specification’s theoretical outline but were broken in every real browsing and assistive technology environment. A deeply nested <section> containing an h1 was announced to screen reader users as a top-level heading — the same level as the page title — regardless of its visual or logical position in the document.

Why the Algorithm Failed to Ship

Browser implementers faced real obstacles. The algorithm required that heading level be computed at render time based on sectioning element nesting — a stateful, context-dependent operation more complex than the existing flat heading model. More significantly, the algorithm had to account for the existing web: billions of pages using h1 through h6 with the traditional meaning. Any implementation risked changing the perceived heading structure of existing documents, breaking screen reader users’ navigation on pages that currently worked.

The WHATWG removed the document outline algorithm from the HTML specification in 2022, acknowledging that it had been “a feature that was never implemented.” The associated note in the current spec is direct: authors should not rely on the outline algorithm; heading levels (h1h6) must be used to convey structure explicitly.

This is a case study in the distance between specification intent and browser reality — and a reminder that “the spec says so” is not sufficient grounds for a production decision.

What Sectioning Elements Actually Do

The removal of the outline algorithm does not make article, section, nav, and aside useless. These elements carry semantic meaning that assistive technologies and search engines do use — just not for heading hierarchy.

<main> identifies the primary content region of a page. Screen readers expose this as a landmark; users can jump directly to it. <nav> marks navigation blocks. <aside> identifies supplementary content. <article> signals a self-contained composition — a blog post, a comment, a product card — that could stand independently. <section> groups thematically related content, typically with its own heading.

These elements create ARIA landmark regions, which are a separate navigation mechanism from headings. A user can jump between landmarks — main, navigation, complementary — without scanning heading by heading. This is genuinely useful. For an in-depth look at how these elements interact with the browser’s accessibility tree, see the HTML semantics article.

What sectioning elements do not do, in any browser that exists today, is modify how heading levels are interpreted. An h2 is always a level-two heading. An h1 is always a level-one heading. Sectioning element depth has no effect on the heading level exposed to screen readers or parsed by search engines.

The h1-Per-Page vs. h1-Per-Section Question

The HTML5 specification, while the outline algorithm was still in it, recommended that each <article> and <section> could begin with an h1. The current specification is more measured: it acknowledges both approaches but notes that the multiple-h1 pattern only makes sense if the outline algorithm is implemented — which it is not.

The practical answer for real-world development is one h1 per page.

A single h1 should describe the page’s primary topic. It is typically the first heading in the <main> region. It is the heading that search engines weight most heavily as the primary topic signal, and it is the anchor from which users orient themselves when they arrive at the page.

Every other heading — for every section, sidebar that has a title, or sub-topic block — should use h2 through h6 according to its depth in the actual content hierarchy. A section heading that is logically a sub-heading of the page topic should be an h2. A heading that introduces a sub-topic within that section should be an h3.

This is not a speculative best practice. It is what works in every browser, every screen reader, and every search crawler available today.

“Skip to Main Content” and Document Structure as Navigation

The heading outline is one layer of document navigation for assistive technology users. Another is the skip link — a visually hidden (but focusable) anchor element placed before the main navigation that links to the <main> content region.

<a href="#main-content" class="skip-link">Skip to main content</a>
<nav><!-- site navigation --></nav>
<main id="main-content">
  <h1>Page Title</h1>
  <!-- content -->
</main>

Without a skip link, keyboard-only users — including screen reader users and users who navigate by tab key — must tab through every navigation item before reaching page content on every page load. On a site with a 40-item navigation, this is a significant barrier.

.skip-link {
  position: absolute;
  transform: translateY(-100%);
  transition: transform 0.2s;
}

.skip-link:focus {
  transform: translateY(0%);
}

The skip link becomes visible on focus — meeting WCAG 2.4.1 (Bypass Blocks) — but does not disrupt the visual layout for mouse users who never trigger it.

The combination of a skip link, semantic landmark elements, and a well-sequenced heading outline creates multiple independent navigation pathways into a document. A screen reader user can jump to the main landmark, then navigate headings within it. Or they can jump directly to the third h2 on the page. Or they can search for specific text. Each mechanism complements the others.

Validating Your Document Outline

Visual inspection of a page does not reliably reveal heading hierarchy problems. A heading styled to look like body text, or a decorative element incorrectly marked as a heading, is invisible to a visual review but obvious in an outline view.

The HeadingsMap browser extension (available for Chrome and Firefox) renders the heading outline of any page as a tree — showing level, nesting, and the full heading text. Gaps in the hierarchy (a jump from h1 to h4) appear immediately. Duplicate h1 elements are visible. Headings used outside of content hierarchy — in navigation, footers, or widgets — show up in context.

Running HeadingsMap on your pages during development is faster than manual ARIA audit tools for catching heading sequence problems. It is also useful for auditing competitor or client pages to understand their structural approach.

The W3C’s Nu HTML Checker will catch some heading-related issues, though it does not validate logical hierarchy — only syntactic validity. It will not warn you that your h1 appears after three h2 elements, but it will catch malformed markup that produces unexpected heading output.

For automated accessibility testing pipelines, axe-core includes rules for heading order and landmark structure. Running axe as part of a CI workflow catches regressions before they ship.

Building Headings That Compose

One practical challenge with strict heading hierarchy is component reuse. A card component used on a page where cards appear below an h2 section heading should use h3 for the card title. The same card component used at the top level of a page might need an h2. Hard-coding heading level inside a component breaks the hierarchy in one context or another.

Several approaches handle this:

Heading level as a prop. In React, Vue, or any component-based framework, accept the heading level as a parameter and render the appropriate element:

function Card({ title, headingLevel = 2, children }) {
  const Heading = `h${headingLevel}`;
  return (
    <article>
      <Heading>{title}</Heading>
      {children}
    </article>
  );
}

The consuming page passes headingLevel={3} when cards are nested under section headings, headingLevel={2} when they are top-level.

Context-based heading level. Some design systems implement a heading context that tracks nesting depth and renders the appropriate level automatically. This requires discipline in how the context is set at each nesting boundary, but it makes components genuinely composable without props threading.

Neither approach is universal. The important constraint is that the rendered HTML must produce a valid sequential outline — however you get there. The technique is secondary to the output.

The relationship between heading structure and other semantic HTML decisions — how landmark elements nest, how ARIA roles supplement native semantics, how interactive widgets communicate state — is covered in the HTML semantics article. The heading outline is one layer of a larger accessibility surface, and understanding how those layers interact is where the real craft lies.