Fix accessibility issue with scrollable code blocks#343
Fix accessibility issue with scrollable code blocks#343hippotastic merged 2 commits intoexpressive-code:mainfrom ruslanpashkov:add-aria-region-role
Conversation
✅ Deploy Preview for expressive-code ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
hippotastic
left a comment
There was a problem hiding this comment.
LGTM! Thank you very much for this fix and the detailed explanation.
|
Hey @ruslanpashkov! Could you provide some links documenting your arguments for the change made in this PR? I’m a bit doubtful about making code blocks landmark regions just because they’re scrollable. A landmark region is supposed to be something that makes sense to navigate to directly, without other page context, and a code block is usually presented in context. Adding and removing landmark regions dynamically could be particularly confusing for users. Additionally, in my testing with VoiceOver, For example, if I navigate to https://expressive-code.com/upgrading/ and make the viewport narrow enough to make code blocks scrollable, none of these code blocks show up in VoiceOver’s landmark navigation pane: To make them appear, they need to be accessibly labelled using For Expressive Code code blocks with a Given that this PR introduces errors in audit tools like |
|
Hey @delucis! Thank you for your feedback - you're absolutely right about the problem with unlabelled landmark elements. But the issue is that we need a Let me try to clarify. You correctly pointed out the landmark problem, and even adding proper aria labels here would create more noise for screen readers than actual benefit. Your VoiceOver research is also spot on — while some screen readers might read this block as a region, it doesn't add any real value for them. Plus, During my audit, I found a 4.1.2 Name, Role, Value compliance issue on these elements because they don't have a semantic tag appropriate for interactive elements (which our code block is, since it's a scrollable element). I decided to check this with Arc Toolkit and it turned out to be correct - it gave me the same message:
So it turns out that landmark roles are inappropriate in this situation, but we still need to explicitly define the element's role. I researched what value would be more appropriate in this situation and found that Eric Bailey recommends using
Looks like it could be a good solution, but I also found this post about I think changing I think we should go with |
|
Thanks for the additional context and links. The I guess the In your testing what differences did you see between no |
|
Shared this with some of the Astro maintainers and @OliverSpeir dug up a good example over at Microsoft Learn. For example: https://learn.microsoft.com/en-us/training/modules/dotnet-dependencies/3-exercise-dependency They use <pre role="group" aria-label="Horizontally scrollable code" tabindex="0">
<code>
...
</code>
</pre>I chatted with one of the Microsoft Learn team on this topic last year where we concluded this was a stopgap while waiting for all browsers to make scrollable regions focusable by default. Chrome joined Firefox earlier this year, so hopefully soon all |
|
Currently, labeling scrollable elements is considered a best practice, but it is not mandatory for WCAG compliance. If we want a great user experience, we need ARIA labeling. However, it lacks translation support, though it is probably still better than nothing, especially in a code block context. I think the best solution here is to add a generic It will resolve the accessibility issue in tools like VoiceOver and NVDA (although JAWS reads this block even without the defined |
|
Yeah, sounds like a decent plan. 👍 Expressive Code does at least include APIs for localization, so users can adjust the label for multilingual use even if |



We had a WCAG compliance issue where scrollable code blocks weren't properly accessible to screen readers and other assistive technologies.
What was wrong?
When code blocks become scrollable, we add
tabindex="0"so people can tab to them and scroll with their keyboard. But we weren't telling screen readers what kind of interactive element this is - it was just "some interactive thing" with no clear purpose. This violates WCAG 4.1.2 Name, Role, Value.The fix
Now when we add
tabindex="0"to make a code block keyboard-accessible, we also addrole="region"to tell assistive technologies "this is a scrollable content area you can navigate to."Why
role="region"?It's the standard way to mark scrollable content sections. Screen readers understand it well and it doesn't mess with the meaning of our code blocks - it just makes them properly accessible.
What changes?
tabindex="0"androle="region"This is a small change that makes our code blocks work better for everyone using assistive technologies, without breaking anything or changing how they look or behave for other users.