Level-Setting Heading Levels
TL;DR: Avoid setting heading levels greater than six (6). This applies whether using aria-level
or the proposed headingstart
HTML attribute. Use HTML <h#>
elements whenever possible.
ARIA
The aria-level
attribute, when applied to headings (or nodes with the heading
role) lets authors set an integer value for a heading level. While aria-level
has been in the ARIA spec since 1.0, it had this note added in the ARIA 1.3 draft:
On elements with role
heading
, values foraria-level
above 6 can create difficulties for users. Also, at the time of this writing, most combinations of user agents and assistive technologies only supportaria-level
integers 1-9 on headings.
This note is the outcome of the ARIA Working Group declining to impose a 1–6 integer limit on aria-level
in February 2023. Instead it was based on support at the time.
HTML
HTML has always had headings, specifically levels 1 through 6.
While HTML5 tried to make good on an idea originally in the first version of HTML, specifically a document outline algorithm, it proved to be untenable and no browser ever implemented it. In 2016 I wrote about the effort to get it removed from the HTML specification, considering the negative the impact it had on users.
One outcome of that effort, or many outcomes that all failed to get traction until now, is the concept of a heading level offset. This would allow authors to integrate content that already has a heading structure, while dynamically adjusting all those headings based on a cue from the containing document.
The headingstart
attribute as proposed in 2019 (though it went through a few names) is the one getting traction. This shifts the burden from authors to browsers, which is better than users but which still will require work by user’s browser on every load, versus the author’s templates on a single render.
Browsers
Browsers will need to support this new HTML property for it to stand a chance. We can look to current support for aria-level
for insight how well this might work.
Gecko (Firefox) and WebKit (Safari) both support values over two billion, or 2,147,483,647 (simplified as 231−1). Chromium (Chrome, Edge) supports only up to level nine (9). Chromium fixed support for aria-level
above 6, but intentionally not for headings (I’ll get to why).
Meanwhile, Chromium has logged its intent to prototype support for headingstart
. The Chrome Platform Status page goes into more detail. There is no indication it will or won’t support heading levels past 9.
When Chromium encounters a value above 9 or an invalid value, it falls back to a value of 6. Gecko will fall back to 2 for invalid values, unless the value was set on a <h#>
element, in which case it will use the element’s level. WebKit will also fall back to the <h#>
element, but otherwise is fine assigning no level for invalid values — with the exception of aria-level="-1"
, exposed as 4294967295.
AAPIs
The Windows platform accessibility API UI Automation has an upper limit for heading levels, specifically nine (9). I did no digging into Microsoft Active Accessibility (MSAA) nor IAccessible2 (IA2), two other (older) AAPIs on Windows.
Now to get to why Chromium opted not to fix aria-level
for headings. Because of the UIA limitation, Chromium explicitly limits heading levels to 9. As a result, an issue was filed to have Core-AAM limit aria-level
on headings to 9. No change was made and no level restriction is listed at Core-AAM (see the ARIA note above).
Because heading levels from HTML and ARIA are exposed through the same AAPIs, this will impact the proposed headingstart
attribute as well as aria-level
.
Screen Readers
The place where this all mostly shakes out is how heading levels are exposed to screen readers and then by screen readers to users.
NVDA, VoiceOver (macOS and iPadOS), and Orca all seem to handle values up to 231−1, which are provided by the browser. Invalid values are handled by the browser and passed through as level 2 (VoiceOver will give no level) or the <h#>
element level.
JAWS cannot handle any level above 6, as filed in 2019. Perhaps a bit more troubling is that JAWS may ignore aria-level
on <h#>
elements.
TalkBack does not like levels above 6. When paired with Firefox it announces no level, but lean’s on Chrome’s bug to announce 2.
In Narrator, any headings (via HTML or ARIA) with a level greater than 9 are no longer announced as headings. If you have an invalid aria-level
, it may concatenate the following content with it and announce it all as a heading at level 2.
Tests
You don’t need to take my word for it. I made a test page (debug mode) and included my results. My testing kit for this post:
- Firefox 125
- NVDA 2024.1
- Orca on Ubuntu 22.04.2 LTS
- Narrator Win11 23H2
- TalkBack 14.2
- Chrome 124
- JAWS 2024.2403.3
- NVDA 2024.1
- TalkBack 14.2
- Edge 124
- Narrator Win11 23H2
- Safari 17.4
- VoiceOver macOS 14.4.1
- VoiceOver iPadOS 17.4.1
See the Pen ARIA Heading Level Test by Adrian Roselli (@aardrian) on CodePen.
Verdict
- Until JAWS and TalkBack fix their bugs, probably don’t do / allow any heading levels higher than 6.
- And then, unless UIA (and Chrome and probably Narrator) changes its limitation, probably don’t do / allow any heading levels higher than 9.
- Using a heading (probably
<h6>
) witharia-level
for any levels above 6 is safer than roleing up another element witharia-level
. - If you are hoping
headingstart
will resolve your heading level problems in a hands-off way with imported or user-generated content, you may end up creating confusion and WCAG risk for the reasons listed in this post (and maybe others). - If you need more than two billion one-hundred forty-seven million four-hundred eighty-three thousand six-hundred forty-seven heading levels, you may need to hire a copywriter.
Related
- There Is No Document Outline Algorithm, 29 August 2016
- Scott O’Hara’s Testing heading levels beyond 6, 22 October 2019
- Heading off confusion: When do headings fail WCAG? 17 March 2020 by David Swallow
- Blaming Screen Readers 🚩×5, 16 October 2021
- Irrational Headings, 21 July 2022
- Steve Faulkner’s h7-h9 via aria-level elements test page, 28 March 2024
- A11y Support Test: ARIA headings greater than level 6, 31 January 2024
- Tackling The Web’s Oldest Problem, 30 Apr 2024 with Brian Kardell, Eric Meyer, and Keith Cirkel
2 Comments
Typo? “for it so stand a chance”.
In response to .It was, thanks!
Leave a Comment or Response