docusaurus icon indicating copy to clipboard operation
docusaurus copied to clipboard

Accessibility checkers have a problem with the placement of the h1 tag

Open mclarty opened this issue 6 months ago • 5 comments

Have you read the Contributing Guidelines on issues?

Prerequisites

  • [x] I'm using the latest version of Docusaurus.
  • [x] I have tried the npm run clear or yarn clear command.
  • [x] I have tried rm -rf node_modules yarn.lock package-lock.json and re-installing packages.
  • [x] I have tried creating a repro with https://new.docusaurus.io.
  • [x] I have read the console error message carefully (if applicable).

Description

Accessibility checkers (such as SiteImprove) are flagging each page using the blog layout as not adhering to "accessibility best practices" with the following note:

Page does not start with a level 1 heading A level 1 heading h1 tells the user what the page is about before they decide to navigate through the content.

Headings are used to structure content into a hierarchy of importance. If a page starts with a different heading level, it can cause confusion for the user.

When analyzing the HTML output from Docusaurus, the sidebar (aside) is rendered before the main content (main) and the h3 tag in the sidebar is being detected as the first header in the HTML source. By removing the use of h3 in the sidebar and replacing with a div class specific to the sidebar, accessibility checkers (and screen readers and other assistive devices) will see the use of h-tags in the main content as the only actual headings on the page.

Source example below:

<div class="row">
    <aside class="col col--3">
        <nav class="sidebar_re4s thin-scrollbar" aria-label="Blog recent posts navigation">
            <div class="sidebarItemTitle_pO2u margin-bottom--md">Recent posts</div>
            <div role="group">
                <h3 class="yearGroupHeading_rMGB">2025</h3>
                <ul class="sidebarItemList_Yudw clean-list">

                	[...]

                </ul>
            </div>
        </nav>
    </aside>
    <main class="col col--7">
        <article class="margin-bottom--xl">
            <header>
                <h2 class="title_f1Hy"><a href="/blog/item1/">Article Title</a></h2>

                [...]

            </header>
            <div class="markdown">
                <p>Article body.</p>
            </div>

            [...]

        </article>
    </main>
</div>

Related to this -- the blog index page does not contain an h1 tag altogether.

Reproducible demo

No response

Steps to reproduce

  1. Publish a Docusaurus site using docusaurus-theme-classic and create a blog page.
  2. Review the HTML code.

Expected behavior

The first header tag on a blog page should be an h1 that conveys the article title.

An h1 tag on the blog index (e.g., recent posts) page should be an h1 that conveys the page title.

Actual behavior

The first header tag to occur on the blog pages is an h3 in the sidebar.

No h1 tag exists on the blog index page.

Your environment

  • Public source code:
  • Public site URL:
  • Docusaurus version used:
  • Environment name and version (e.g. Chrome 89, Node.js 16.4):
  • Operating system and version (e.g. Ubuntu 20.04.2 LTS):

Self-service

  • [ ] I'd be willing to fix this bug myself.

mclarty avatar Jun 12 '25 14:06 mclarty

Hey, I'm not an accessibility expert but this indeed seems weird to use an <h3> for the "year groups" of our blog sidebar.

However,

Accessibility checkers (such as SiteImprove)

Can you tell me which other accessibility checker report this error? How can I verify this myself?

I've come to not trust blindly what a single accessibility tool report, because they may all behave differently in practice.

Also, do you have any reference document from an authoritative source that explains that it's bad to use an h3 in this <aside> context? I'm not sure but I think it's fine to use headings outside the main content.

See for example: https://www.w3.org/WAI/tutorials/page-structure/headings/#:~:text=used%20like%20this.-,Main%20heading%20after%20navigation,-In%20this%20second


TLDR: can you help me and somehow find a way to prove that it's not your specific tool that is wrong and reporting a false positive.

slorber avatar Jun 13 '25 17:06 slorber

When analyzing the HTML output from Docusaurus, the sidebar (aside) is rendered before the main content (main) and the h3 tag in the sidebar is being detected as the first header in the HTML source. By removing the use of h3 in the sidebar and replacing with a div class specific to the sidebar, accessibility checkers (and screen readers and other assistive devices) will see the use of h-tags in the main content as the only actual headings on the page.

Unrelated to the issue being reported, I also feel that the sidebar with years and other blog posts could also semantically be a nav item since it allows you to navigate to other posts while also changing the URL

vipulbhasin23 avatar Jul 15 '25 14:07 vipulbhasin23

We are seeing similar issues on https://developer.overheid.nl/communities/

index.mdx (source):

# Communities

Hieronder een overzicht van developer communities.

```mdx-code-block
import DocCardList from '@theme/DocCardList';

<DocCardList />
```

Rendered output (cut some SVG elements out for readability):

<header>
    <h1>Communities</h1>
</header>
<p>Hieronder een overzicht van developer communities.</p>
<section class="row">
    <article class="docCardListItem_d7Ib col col--6">
        <a class="card padding--lg cardContainer_S8oU" href="/communities/code-for-nl">
            <h3 class="cardTitle_HoSo"><!-- -->Code for NL</h3>
            <p class="cardDescription_c27F">Code for NL is een netwerk van developers, designers en andere experts die
                samenwerken aan digitale toepassingen voor een open, eerlijke en inclusieve samenleving.</p>
        </a>
    </article>
    <article class="docCardListItem_d7Ib col col--6">
        <a class="card padding--lg cardContainer_S8oU" href="/communities/common-ground">
            <h3 class="cardTitle_HoSo"> <!-- -->CommonGround</h3>
            <p class="cardDescription_c27F">Gemeenten werken samen met een community van betrokkenen partijen aan
                bouwstenen, zoals softwaretoepassingen, technische componenten of standaarden voor gegevensuitwisseling.
            </p>
        </a>
    </article>
</section>

Note that, despite DocCard setting the heading to h2 (https://github.com/facebook/docusaurus/blob/a4c33bfea56b231b302adbf819a45c2de217a01d/packages/docusaurus-theme-classic/src/theme/DocCard/index.tsx#L79), the heading is rendered as h3.

When we run npx axe https://developer.overheid.nl/communities/ we get the following output:

Running axe-core 4.10.3 in chrome-headless

Testing https://developer.overheid.nl/communities/ ... please wait, this may take a minute.

  Violation of "heading-order" with 1 occurrences!
    Ensure the order of headings is semantically correct. Correct invalid elements at:
     - a[href$="code-for-nl"] > h3
    For details, see: https://dequeuniversity.com/rules/axe/4.10/heading-order

1 Accessibility issues detected.

Which is a correct finding, since the heading order is h1 for "Communitities" and then h3 for "Code for NL". It should be h2 for "Code for NL", which is what DocCard wants it to be, yet it isn't rendered as such.

This is for Docusaurus 3.8.1 (latest version at time of writing).

TimvdLippe avatar Aug 18 '25 09:08 TimvdLippe

@TimvdLippe are you sure you didn't swizzle the components?

Because we don't see this behavior on our own website: https://docusaurus.io/docs/sidebar/items#embedding-generated-index-in-doc-page

slorber avatar Aug 24 '25 10:08 slorber

Ah, I am not familiar that much with Docusaurus and didn't know swizzling. Turns out that you are correct. Haven't been able to figure out how to fix the issue, given that the h1 header is generated by Docusaurus. I tried swizzling https://github.com/facebook/docusaurus/tree/main/packages/docusaurus-theme-classic/src/theme/DocCategoryGeneratedIndexPage (which is marked as unsafe, I know) to make it a h2, but that didn't have any effect. Will have to debug further what's going on with our setup.

TimvdLippe avatar Aug 27 '25 13:08 TimvdLippe