---
title: 'Heading Hierarchy'
source: 'https://academia.sh/en/courses/web-fundamentals-and-html/heading-hierarchy'
course: 'Web Fundamentals and HTML'
language: en
updated: '2026-08-17T18:09:31+00:00'
license: 'CC BY-SA 4.0'
---

# Heading Hierarchy

Heading level's function as a structural declaration, extracting the document's outline, the consequence of skipping a level, and headings' use as a navigation tool.

The head section is complete; writing the body begins. The body's first structural decision is
headings: the tags that declare which sections the document is divided into and these
sections' level relative to one another.

There are six heading elements: `h1` through `h6`. The number gives the heading's **level** —
the first level is the topmost. This number is not a font size; it declares nesting depth.

## A Heading Is a Structural Declaration

A heading element does two jobs. It names the content that follows it, and it declares that
content's depth in the document. The second job is carried by the level number.

It is enough to think of a book's table of contents: chapter titles, section titles, and
subsection titles are written at different indentation levels, and the indentation shows which
subsection belongs to which chapter. In HTML, the level number is indentation's counterpart.

This information is used. Screen readers offer navigation from heading to heading; instead of
listening to the document from the start, the user scans the outline and jumps to the section
they are interested in. Content-extraction tools divide the document by its headings.
Indexers give heading text a different weight than body text.

## Extracting the Outline

Heading levels define a tree, and this tree can be computed from the document.

```js
// heading.mjs — extracts the outline from a heading-level sequence
const document_ = `
<h1>North Slope Station</h1>
<h2>Location</h2>
<h2>Measured Quantities</h2>
<h3>Temperature</h3>
<h3>Relative Humidity</h3>
<h2>Data Access</h2>
<h4>File Format</h4>
`;

const headings = [...document_.matchAll(/<h([1-6])>([^<]*)<\/h\1>/g)].map((e) => ({
  level: Number(e[1]),
  text: e[2],
}));

let previous = 0;
const warnings = [];
const number = [];
for (const heading of headings) {
  if (previous !== 0 && heading.level > previous + 1) {
    warnings.push(`h${previous} then h${heading.level}: h${previous + 1} skipped (${heading.text})`);
  }
  number.length = heading.level;
  number[heading.level - 1] = (number[heading.level - 1] ?? 0) + 1;
  const label = [...number].map((s) => s ?? 0).join(".");
  console.log("  ".repeat(heading.level - 1) + label + "  " + heading.text);
  previous = heading.level;
}

console.log("--- audit ---");
console.log("heading count :", headings.length);
console.log("h1 count      :", headings.filter((b) => b.level === 1).length);
for (const warning of warnings) console.log("warning       :", warning);
```

```
1  North Slope Station
  1.1  Location
  1.2  Measured Quantities
    1.2.1  Temperature
    1.2.2  Relative Humidity
  1.3  Data Access
      1.3.0.1  File Format
--- audit ---
heading count : 7
h1 count      : 1
warning       : h2 then h4: h3 skipped (File Format)
```

The last heading makes the flaw visible. While `Data Access` is at the second level, `File
Format` was written at the fourth level; the third level was skipped. In the numbering, this
shows up as an empty digit, in the form `1.3.0.1`: there is a level in the outline with no
counterpart.

## The Consequence of Skipping a Level

A skipped level leaves a gap in the outline. A user navigating the document from heading to
heading expects a subsection that does not exist between `Data Access` and `File Format`, and
does not find it. The result is not a visual flaw, it is a wrong structural declaration.

The reason for the skip is usually presentational: the author found a fourth-level heading's
default appearance more suitable. This is the layer violation defined in the first lesson. The
correct fix is to choose the level by structure and correct the appearance in the presentation
layer.

There is no rule in the reverse direction: skipping while the level **decreases** is not a
flaw. Returning to the second level after a third-level section declares that the subsection
has ended and a new higher-level section has begun; this is an ordinary closing.

## How Many First-Level Headings in a Document

There are two defensible approaches on this question, and both are in use.

**The single-`h1` approach**: the document has only one first-level heading, and it names the
document's subject. Everything else is beneath it. This approach makes the outline a
single-rooted tree and makes it easy to summarize the document outside its context.

**The per-section-`h1` approach**: every sectioning element restarts its own heading level,
and level is computed from nesting. The outline computation this approach relies on has not
been consistently supported across screen-reader implementations.

This course follows the first approach: a single `h1` in the document, with headings beneath
it that follow numeric order. The justification is not theoretical superiority, it is that
implementations interpret this arrangement consistently. A structural declaration's value
depends on the tools reading it drawing the same conclusion from it.

## A Heading's Content

A heading element carries text and allows inline markup: a heading can contain an
abbreviation, a code fragment, or emphasis. What it should not contain is content that belongs
to a separate section — a heading names a section, it is not the section's content itself.

Heading text should also be understandable outside its context. A user navigating from heading
to heading hears only the headings, without seeing the body text. Headings like "Details,"
"More," or "Section 3" carry no information in this use.

If a document has text that is not written with a heading element but visually stands like a
heading, that section is not in the outline. The reverse holds too: text placed in a heading
element only to look large adds a section to the outline that does not exist.

## The Subheading Problem

Writing a short introductory line beneath a heading, one that complements it, is a common
requirement. If this line is placed in a second-level heading element, a section that does not
exist is added to the outline: while navigating, the user expects a subsection, but there is
only an introductory sentence.

```html
<h1>North Slope Measurement Station</h1>
<h2>At 1840 meters, four quantities</h2>   <!-- adds a fake section to the outline -->
```

The correct way to write it leaves the introductory line outside the heading element and keeps
the two together:

```html
<header>
  <h1>North Slope Measurement Station</h1>
  <p>At 1840 meters, four quantities</p>
</header>
```

Here the outline has only one entry; the introductory line is a paragraph, and its visual
relationship with the heading is established in the presentation layer. The `header` element
used here is the subject of the next topic; its job here is to group the two elements as a
single introductory block.

The same reasoning applies to opening a second heading element just to show part of the
heading text smaller. If an entry is meant to be added to the outline, a heading element is
used; if not, it is not used. Appearance is not the criterion for this decision.

## The Station Document's Outline

The body of the document developed throughout the course is divided into sections with
headings:

```html
<body>
  <h1>North Slope Measurement Station</h1>
  <p>An automated measurement station built at an elevation of 1840 meters above sea level.</p>

  <h2>Location and Setup</h2>
  <p>The station sits on the middle stretch of a north-facing slope.</p>

  <h2>Measured Quantities</h2>
  <h3>Temperature</h3>
  <p>The measurement interval is ten minutes.</p>
  <h3>Relative Humidity</h3>
  <p>The measurement interval is ten minutes.</p>

  <h2>Data Access</h2>
  <p>Records are published as daily files.</p>
</body>
```

This skeleton is the structure the rest of the document will be built on. In the following
lessons, each section's content will be filled in; the heading arrangement will not change.

## Summary

- Heading level is not a font size, it is structural data that declares depth in the document.
- Headings define an outline; this outline is used by navigation, content-extraction, and
  indexing tools.
- Skipping while level increases leaves a gap in the outline with no counterpart; skipping
  while level decreases is not a flaw.
- The approach of keeping a single first-level heading in the document is followed in this
  course because of implementations' consistent interpretation.
- Heading text should be understandable outside its context too; a user navigating from
  heading to heading does not see the body.

## Next Step

Headings named the sections; paragraphs will fill their content. Paragraph text itself is
structureless too: why a piece is emphasized, what an abbreviation stands for, where a
quotation comes from is lost unless declared. The next lesson takes up inline markup, and
along the way shows a transformation the parser applies to text: what happens to whitespace
and line breaks in the source text.
