Using Heading Structure Correctly (h1-h6)
AI generated
A11Y
WCAG
Accessibility · Screen Readers · Semantics · WCAG
Using Heading Structure Correctly (h1-h6)
A navigable outline, not just bold running text

A correct heading structure from h1 to h6 turns a web page into a navigable table of contents for screen reader users, who jump from heading to heading with a keyboard shortcut. Skipping levels just for font size quietly breaks that navigation. This article covers the practical one h1 convention, correct hierarchies and fast audit methods for Magento and Hyva stores.

14 min. read h1-h6 · Screen Reader Navigation WCAG 2.1 SC 1.3.1 · 2.4.6 · Magento 2.4.8 · Hyva Theme

1. Why heading structure determines navigability

Sighted users skim a page visually: large bold text signals a new section, smaller sub headings organize the details underneath. Screen reader users do not have that visual shortcut. Instead they rely entirely on the programmatic heading structure in the HTML. Assistive technologies like JAWS, NVDA and VoiceOver each offer a dedicated shortcut, usually the H key, that lets users jump from one heading to the next without listening to the entire page read aloud. WebAIM surveys have consistently shown for years that the majority of screen reader users name this exact jump navigation as their preferred method for getting a first overview of an unfamiliar page.

That makes the heading structure the page's actual table of contents, not just a typographic formatting choice. When a genuine hierarchy is missing or inconsistent, the screen reader user loses precisely that orientation, while the page looks completely unremarkable to sighted visitors. The mistake usually goes unnoticed day to day because no visual break occurs, only a structural one. That very invisibility is what makes heading mistakes one of the most common, and at the same time one of the most easily avoidable, barriers on the web.

2. Semantic meaning versus visual styling

The central thinking error with headings: developers pick the tag level h1 through h6 based on the desired font size, not based on the content's actual position in the document. An h4 gets used because it looks smaller than an h2 in the default stylesheet, even though the section is clearly a second level in the outline. Sighted users never notice, but for the accessibility API that communicates structure to screen readers, it is a direct break: the level in the document tree no longer matches the actual content hierarchy.

The clean solution separates the two responsibilities strictly: the HTML level h1 through h6 describes only the position in the content tree, while CSS classes control the visual size, weight and spacing. An h2 is allowed to look just as small as an h5, as long as the semantic level matches the actual outline. Tailwind utility classes are particularly well suited for this, since they decouple size and tag completely without needing separate CSS selectors per heading level.


<!-- Semantic level and visual size are two different things -->

<!-- WRONG: h5 chosen only because the text should look smaller -->
<h5 class="font-bold text-2xl mt-8">New Summer 2026 Collection</h5>
<p>Lightweight fabrics, clean cuts, limited runs.</p>

<!-- RIGHT: h3 keeps the correct level in the document tree, -->
<!-- the size comes purely from the utility class -->
<h3 class="font-bold text-2xl mt-8">New Summer 2026 Collection</h3>
<p>Lightweight fabrics, clean cuts, limited runs.</p>

3. Exactly one h1 per page: the practical convention

The HTML5 specification technically allows multiple h1 elements per page, as long as they sit inside separate sectioning elements like article or section and a so called outline algorithm derives the levels from that nesting. In practice, no mainstream browser and no screen reader fully implements this theoretical outline algorithm. For JAWS, NVDA and VoiceOver users, what counts is simply the actual tag level in the DOM, regardless of the surrounding sectioning element.

That is why a simple, robust convention has taken hold in practice: exactly one h1 per page, naming the page title or the central topic, such as the product name on a product detail page or the category name on a category page. Every further section starts at h2 and works downward. This convention is not an official WCAG requirement, but it is the most reliable way to give screen reader users an unambiguous answer to where they currently are, the moment they press the 1 key to jump straight to the next h1.

4. Keep the hierarchy: never skip levels

Alongside the one h1 convention, the second core rule is this: heading levels must never be skipped when descending. An h2 may only be followed by an h3 as the next deeper level, never directly by an h4. The reason again lies in jump navigation: a screen reader user working systematically from level to level expects an unbroken chain. When an intermediate level is missing, it creates the impression that an entire section has vanished, even though the content is actually there, just filed under the wrong level.

Jumping back up to a higher level, by contrast, is unproblematic: after several h3 sections, moving straight back to a new h2 is the normal, correct way to close out a subsection. The rule only concerns descending in the hierarchy. Anyone planning a redesign who wants a smaller font size for a specific area should always ask the content question first: what is the actual outline level of this section, regardless of how it should eventually look.

5. Implementation in Magento and Hyva templates

In Magento stores, heading mistakes tend to appear in three places: the theme layout itself, CMS blocks maintained through the WYSIWYG editor, and widget output from third party modules. The WYSIWYG editor in the Magento backend lets editors pick any heading level freely, without regard for the surrounding page structure. The result: a CMS block with an h2 right in the middle of a product detail page that already has its own h2 for "Description", or a marketing widget that starts with h1 out of habit.

In Hyva Theme, structure can be controlled directly in the phtml template, since there is no block generated markup like in classic UI Components. The product detail page sets the product name as the single h1, while sections like description, technical data or reviews consistently start at h2. Editors additionally benefit from a CMS guideline that restricts WYSIWYG headings to start at h3, so that editorial content can never collide with the page structure.


<!-- Hyva phtml: category page with a correct heading hierarchy -->
<div class="category-view">
    <h1 class="text-3xl font-bold"><?= $block->escapeHtml($category->getName()) ?></h1>

    <?php if ($block->getCategoryDescription()): ?>
        <div class="category-description mt-4">
            <?= /* @noEscape */ $block->getCategoryDescription() ?>
        </div>
    <?php endif; ?>

    <h3 class="text-xl font-semibold mt-8">Products in this category</h3>
    <div class="product-grid">
        <?= $block->getChildHtml('category.product.list') ?>
    </div>

    <?php if ($block->getRelatedCategories()): ?>
        <h3 class="text-xl font-semibold mt-8">Related categories</h3>
        <?= $block->getChildHtml('category.related') ?>
    <?php endif; ?>
</div>

6. Working together with ARIA landmarks and roles

ARIA landmarks like main, nav and aside complement heading structure, they do not replace it. Landmarks answer the question "which area of the page is this", headings answer "what content outline does this area have". A screen reader user often moves back and forth between both navigation types: first jumping via landmark to the main area, then using the heading key to move through the sections there. When either level is missing, the other remains a fallback, but a considerably less precise one.

For interactive components that cannot use a native h1 through h6 for design reasons, such as a div acting as an accordion title through JavaScript, role="heading" combined with aria-level="3" can force an equivalent semantic level. This should remain the exception, though: a native h3 element is always more robust, because it works without extra ARIA attributes and is automatically recognized correctly by every tool. Automated audit tools like axe-core flag skipped levels regardless of whether they were produced natively or via an ARIA role.


{
  "id": "heading-order",
  "impact": "moderate",
  "description": "Ensures the order of headings is semantically correct",
  "help": "Heading levels should only increase by one",
  "helpUrl": "https://dequeuniversity.com/rules/axe/4.9/heading-order",
  "nodes": [
    {
      "html": "<h4 class=\"font-bold text-2xl\">New Summer 2026 Collection</h4>",
      "target": [".category-view > h4"],
      "failureSummary": "Fix any of the following: Heading order invalid, expected h2 or h3 but got h4"
    }
  ]
}

7. Auditing: browser tools and screen reader testing

The fastest way to check a heading structure is a free browser extension like HeadingsMap, or the accessibility panel built into the Chrome and Firefox developer tools. HeadingsMap displays a page's entire outline at a glance as an indented tree and immediately flags skipped levels visually. Anyone who cannot or does not want to install an extension gets the same result with a few lines of JavaScript straight in the browser console, which also fits nicely into a pre deployment script.

Automated tools like axe-core or Lighthouse reliably catch structural mistakes such as skipped levels or multiple h1 elements, but they cannot tell whether a heading actually makes sense as content. That is why a short manual test with NVDA or VoiceOver rounds out the automated check: press the H key to move through the page and listen along to whether the outline read aloud actually makes sense to someone who cannot see the page. This test rarely takes longer than five minutes per page type.


// Run in the browser console: prints the page's heading outline
(function printHeadingOutline() {
  const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
  let lastLevel = 0;

  headings.forEach((heading) => {
    const level = parseInt(heading.tagName.substring(1), 10);
    const indent = '  '.repeat(level - 1);
    const skipped = level - lastLevel > 1 && lastLevel !== 0;
    const marker = skipped ? '  <-- level skipped' : '';

    console.log(`${indent}h${level}: ${heading.textContent.trim()}${marker}`);
    lastLevel = level;
  });

  const h1Count = document.querySelectorAll('h1').length;
  console.log(`\nFound h1 elements: ${h1Count}${h1Count !== 1 ? '  <-- should be exactly 1' : ''}`);
})();

8. Common mistakes in practice

The most common mistake is choosing the heading level for purely visual reasons, closely followed by div or span elements styled bold and large with CSS to look like a heading, while remaining completely unrecognizable as a heading semantically. For screen reader users, such an element simply does not exist in the outline, no matter how prominent it looks visually. Another classic mistake comes from several independently built components on the same page, for example a marketing banner module that starts with h1 by default, combined with the actual page h1 from the theme.

A third common mistake: headings get misused for purely decorative marketing claims, such as <h2>Grab the deal now!</h2> with no real content section underneath. That artificially inflates the outline for screen reader users and dilutes the actual structure. The rule of thumb: a heading always describes the content block that follows it, never just an isolated piece of marketing copy with no associated section.


/* Define size classes independently from the semantic level */
.heading-display { font-size: 2.25rem; font-weight: 800; line-height: 1.2; }
.heading-section  { font-size: 1.5rem;  font-weight: 700; line-height: 1.3; }
.heading-label    { font-size: 1rem;    font-weight: 600; letter-spacing: 0.02em; }

/* An h3 is allowed to look visually like an h1, without changing the level */
h3.heading-display {
  font-size: 2.25rem;
}

/* A div looks like a heading, but semantically it is not one */
/* Screen reader users will not find this element in the outline */
.fake-heading {
  font-size: 1.5rem;
  font-weight: 700;
}

9. Heading patterns compared side by side

The table below summarizes the most important decisions between an unreliable and a correct implementation. Each row describes a scenario that shows up regularly in Magento and Hyva stores.

Scenario Wrong Right Benefit
Smaller text desired h4 instead of h2 for looks h2 with a CSS class for a smaller size Semantic level stays correct
Multiple page areas Every block starts with h1 Exactly one h1, the rest h2 through h6 Unambiguous entry point for screen readers
Subsection nested deeper h2 directly followed by h4 h2 followed by h3 Unbroken jump navigation
Title needs to stand out <p><strong>Title</strong></p> <h3>Title</h3> Shows up in the heading outline
Marketing claim with no section <h2>Grab it now!</h2> with no content below Claim as <p>, h2 only for real sections Outline stays content wise clean

All five scenarios share the same core idea: the choice of heading level should always follow the actual content position in the document, never the desired appearance. Anyone who consistently keeps that separation never has to rebuild headings after the fact when the design changes.

Mironsoft

Web accessibility, WCAG audits and Hyva Theme development for Magento stores

Is your heading structure actually navigable?

We check the heading hierarchy of your Magento or Hyva store with screen reader tests and automated audits, and fix skipped levels, duplicate h1 elements and CMS blocks that break the structure.

Heading audit

Full outline review with axe-core and a manual screen reader test

Theme refactoring

Rebuilding Hyva templates around a clean h1-h6 structure

CMS guidelines

Establishing editorial guidelines for WYSIWYG headings in the backend

10. Summary

A correct heading structure is not a question of looks, it is the page's table of contents for screen reader users who jump straight from one heading to the next with a keyboard shortcut. h1 through h6 describe only the position in the document tree, while CSS classes control size and style. Exactly one h1 per page has become the robust convention, because no mainstream screen reader reliably implements the theoretical HTML5 outline algorithm. Descending into deeper levels must never skip a step, while ascending back to a higher level is always fine.

In Magento and Hyva stores, mistakes usually appear in three places: the theme itself, CMS blocks edited through the WYSIWYG editor, and third party widgets. Browser extensions like HeadingsMap, automated tools like axe-core and a short manual test with NVDA or VoiceOver catch the most common problems within minutes per page type. Anyone who consistently keeps semantic level and visual size separate never has to touch the structure again with the next redesign.

Using Heading Structure Correctly (h1-h6): The Essentials at a Glance

Semantics before looks

The heading level follows the content's position in the document. Size and style are controlled by CSS alone.

Exactly one h1

One h1 per page as a robust convention, since no screen reader fully uses the HTML5 outline algorithm.

Never skip levels

Always use the next level down when descending, never jump two steps deeper at once.

Quick to audit

HeadingsMap, axe-core and a short screen reader test catch mistakes within minutes.

11. FAQ: Using Heading Structure Correctly

1Why does a correct heading structure matter for accessibility?
Screen reader users jump directly between headings with a keyboard shortcut. Headings are effectively the page's table of contents. Without a clean structure, that orientation is lost, unnoticed by sighted users.
2Why should every page have only one h1?
No mainstream screen reader reliably implements the theoretical HTML5 outline algorithm for multiple h1 elements. One h1 per page is the robust practical convention for an unambiguous jump target.
3What happens if I skip levels just for looks?
Jump navigation feels broken, a section seems to be missing even though the content exists, just filed under the wrong level. This makes orientation considerably harder.
4How do screen reader users navigate with headings?
Usually with the H key to jump between headings, plus number keys for specific levels. A rotor or list view also shows the entire outline at a glance.
5Can I use an h3 for visually smaller text?
The level should always follow the content position, not the desired look. For smaller visuals with the correct level, use a CSS class that decouples tag and size.
6How do I quickly audit a page's heading structure?
The HeadingsMap extension, a short console script, or automated tools like axe-core and Lighthouse catch mistakes within minutes.
7What is the difference between visual size and semantic level?
The semantic level is evaluated by screen readers, visual size is pure CSS. Both should be controlled independently of each other.
8How do I implement headings correctly in Hyva templates?
Page title as the single h1 in the phtml template, every section starting at h2, CMS content in the WYSIWYG editor restricted to h3 as the starting level.
9Do ARIA landmarks count as heading levels?
No. Landmarks describe areas of the page, headings describe the content outline within them. Both complement each other but do not replace one another.
10Which WCAG success criteria cover heading structure?
Mainly 1.3.1 Info and Relationships and 2.4.6 Headings and Labels, both at conformance level AA.