Problem/Motivation
The system pager template(s) contain a hardcoded h4.visually-hidden element. In some common contexts, this produces a heading in the document which does not follow heading level order. This is reported as a (best practices) accessibility issue by tools such as aXe.
- https://git.drupalcode.org/project/drupal/-/blob/9.2.x/core/modules/syst...
- https://www.w3.org/WAI/tutorials/page-structure/headings/
- https://dequeuniversity.com/rules/axe/4.3/heading-order
This was raised in Drupal Slack #accessibility channel, see there for some early discussion.
aXe's report is a best practices notification, moderate impact:
Heading levels should only increase by one.
Issue description: Ensures the order of headings is semantically correct
To solve this issue, you need to... Fix the following: Heading order invalid
Steps to reproduce
This affects all default themes in 9.2.x: Bartik, Claro, Olivero, Seven, and Stark.
- Use Devel Generate to generate 50 nodes
- View the default /node view
- Observe that the headings in the document run h1 (page title), h2 (node titles), h4 (pagination), OR
- Run aXe Devtools or other a11y checker
Proposed resolution
Remove the h4 and use a aria-label and/or role on the <nav> element
There's already an aria-labelledby on the <nav>; we could replace that with aria-label and remove the <h4> entirely. This requires that the replacement provide equivalent functionality / accessibility. Is a role also appropriate here? There may be many pagination controls on a single page.
Other options considered:
Replace the h4 with an h2
This replaces one hardcoded value with another, and retains some assumptions about the page (ie that there is an h1 present at all). It probably introduces BC issues for themes which presume h4 for this, and if the pagination element is placed within a subsection it will incorrectly raise the pagination widget to a new second level section.
Make the tag used configurable
This could permit site builders to configure the heading level per View display or other pagination use. (This could be combined with changing the default tag from h4 to another heading level.)
Remaining tasks
User interface changes
Hopefully, increased accessibility. Changes to HTML output.
API changes
Proposed options will change elements in default themes.
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|
Issue fork drupal-3232222
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
xurizaemonComment #3
xurizaemonComment #4
larowlanGiven this is in a twig template, and therefore can be overridden by a theme on a project, I think we're only talking about making core theme's semantically correct w.r.t to structure/heading levels.
So it would be good to use an a11y tool to see which of the core themes (seven/claro/bartik/olivero) have this issue.
Bearing in mind that we can't change markup in minor versions for seven or bartik (as they're stable) nor in stable/stable9.
Comment #5
xurizaemonComment #6
xurizaemon@larowlan, correct. I should clarify that I've set version=9.2.x because that's where I've reproduced it; it looks like this isn't yet fixed in 9.3.x or 10.x and I'm happy for version to be set appropriately, anticipating that we would not change templates in a current release.
I'll check with each of those themes and update.
Comment #7
xurizaemonBartik, Seven, Claro, and Olivero (and Stark) all exhibit this behaviour in Drupal 9.2.x when tested with aXe Devtools in Firefox.
Comment #8
xurizaemonComment #9
xurizaemonComment #10
mikemai2awesome commentedCorrect me if I am wrong, the aria-label method would work just as well since nav is already a landmark.
Otherwise, I think it is reasonable to "make the tag used configurable". The content creator should have full control of information architecture on a given page, the template should not have absolute opinion on the heading.
Comment #11
xurizaemonComment #13
xurizaemonTests have failed for template hashes, will update shortly.
Comment #14
maiam commentedComment #15
maiam commentedhi folks! i'm the accessibility lead at Catalyst IT. Here are my 2 cents:
A heading is meant to demarcate a section (https://www.w3.org/TR/REC-html40/struct/global.html#h-7.5.5 "A heading element briefly describes the topic of the section it introduces"). Are we demarcating a section here? I don't really think we are. I think the
<h4>(and any other<h#>) should be removed entirely.Instead, what is the
<h4>'s purpose here? I think it is being used to indicate to screen reader users that the pagination exists. That's cool, and in which case there are certainly ways we can achieve this.My favourite option is to use
<nav>(which is already being done) since pagination is indeed a way to navigate through the page content. Screen reader users are able to pull up the aria landmarks of a page, "scanning" the page.<nav>accurately reflects the nature of the role of pagination, as well as removes the risk of messing with the page hierarchy without context since this is a reusable component.Note there's no such thing as
role=pagination. With<nav>, built into that element isrole=navigation.Here's a good design pattern for an accessible pagination: https://www.a11ymatters.com/pattern/pagination/ According to this link, I recommend:
Comment #16
xurizaemonThanks Maia for the review & feedback (for transparency, @maiam and I are colleagues).
I did not change the existing label text from "Pagination" to "Pagination Navigation" as IMO that would have translation impact as well.
Have updated tests to account for new hashes on Classy templates (TIL!).
My mistake on role="pagination" I think. I double checked the intent of this statement with Maia directly who said,
So there's an additional suggestion here to remove the
role="navigation"from the nav element; I'm happy to tidy this up while I'm here, or for someone else to do so and add to the MR, but I'll await input from others who might want to comment.Comment #17
xurizaemonComment #18
xurizaemonShould have set this back to NR when I fixed the tests above, I think.
Comment #21
kurttrowbridgeHello! I had brought this issue up today in another project that provides a Drupal design system, so we could implement the same accessibility adjustment there, and conversation there reiterated Maia's suggestion in #15 above: that
role="navigation"is built into the<nav>element by default, so including it is redundant. MDN supports that removal ("Using the<nav>element will automatically communicate a section has a role of navigation. Developers should always prefer using the correct semantic HTML element over using ARIA"), and ARIA's first rule is to not use ARIA in cases where semantic HTML alone does the trick. As such, I committed the removal of thoseroleattributes to the existing merge request. Thanks!Comment #22
xurizaemonThanks @KurtTrowbridge! Appreciate having a second assessment to support the recommended course of action.
Tests had failed due to the template change no longer generating a committed hash; I've rebased the MR, and updated the relevant hash accordingly. (This issue was how I learned that those hashes exist!)
Comment #23
xurizaemonComment #24
xurizaemonAs Gitlab MR URLs are subject to unexpected changes (ref #3204538), I'm attaching a patch copy of MR !1186 as at some earlier revision.
This wants a re-roll anyway, please continue using the MR.
Comment #25
xurizaemonComment #28
xurizaemonA new issue #3333401: Pager h4 causes accessibility flag on many pages has been opened for this with fix targeting Drupal 10 and has already made it to RTBC, and there is then a 10.x scoped stable9 issue #3333418: Fix pager h4 for accessibility on Stable9 to follow up on that one.
Posting this as folks interested in seeing this resolved (10 followers) may want to track those issues (less than 10) also.
Comment #29
mgiffordTagging for WCAG 2.4.6
Comment #30
nicxvan commentedDuplicate of: https://www.drupal.org/project/drupal/issues/3333401