-
Notifications
You must be signed in to change notification settings - Fork 324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ensure code blocks (<pre>) are keyboard focusable #1636
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done self-reviewing
html_string = self.body[-1] | ||
self.body[-1] = html_string.replace("<pre", '<pre tabindex="0"') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is kinda dirty but... it seems to work 🤷
I'll leave it up to the reviewers to decide if it's too dirty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am having a bit of trouble following here - is the goal of these to find and traverse any hidden/nested pre
tags then add the tabindex
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly. When the parent class's visit_literal_block
method is called, it appends an HTML string to self.body
. So the very last item in the self.body
list is just an HTML string containing a bunch of markup that represents the literal block. A lot of the tags in that markup are there to provide syntax highlighting, line numbers, captions, etc. The relevant tags inside that markup are the pre
tags, although I would guess there's only ever one pre
tag. However, I add tabindex="0"
to any pre tag I find because the nature of a pre
tag is that it preserves the whitespace, which means it might be scrollable (depending on how long the lines inside of it are) and should therefore be keyboard-focusable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't seem that "dirty" to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto not dirty just working with what we have
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read something since working on this PR that makes me wonder if this is the right thing to do. The thing I read was about tables but the same could be said about pre-blocks:
Of course, we don't want to make the table container focusable unless its contents overflow. Otherwise we're adding a tab stop to the focus order which doesn't do anything. In my opinion, that would be a fail under 2.4.3 Focus Order. Giving keyboard users elements to focus which don't actually do anything is confusing and obstructive.
Source: Inclusive Components - Data Tables - Only Focusable Where Scrollable
Which makes me wonder if we should put a data attribute on the pre-tag and then check it with JavaScript after it loads to determine if it should really be a tab stop or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
html_string = self.body[-1] | ||
self.body[-1] = html_string.replace("<pre", '<pre tabindex="0"') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am having a bit of trouble following here - is the goal of these to find and traverse any hidden/nested pre
tags then add the tabindex
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I just revisited this PR and realized that I had a bunch of pending comments
html_string = self.body[-1] | ||
self.body[-1] = html_string.replace("<pre", '<pre tabindex="0"') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly. When the parent class's visit_literal_block
method is called, it appends an HTML string to self.body
. So the very last item in the self.body
list is just an HTML string containing a bunch of markup that represents the literal block. A lot of the tags in that markup are there to provide syntax highlighting, line numbers, captions, etc. The relevant tags inside that markup are the pre
tags, although I would guess there's only ever one pre
tag. However, I add tabindex="0"
to any pre tag I find because the nature of a pre
tag is that it preserves the whitespace, which means it might be scrollable (depending on how long the lines inside of it are) and should therefore be keyboard-focusable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a pretty efficient solution. I think another possible route would be to define a "post-transform" which alters the docutils.document before it gets to the translator. But IDK if that would actually be cleaner/easier, and this seems to give the desired result, so 🤷🏻
# If the super method raises nodes.SkipNode, then we know it | ||
# executed successfully and appended to self.body a string of HTML | ||
# representing the code block, which we then modify. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so... docutils raises an exception when the method executes successfully? What happens when it fails? 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would raise a different exception but I'm not sure.
I think it has something to do with the way that docutils traverses the doc tree, see docutils/nodes.py::Node.walkabout()
html_string = self.body[-1] | ||
self.body[-1] = html_string.replace("<pre", '<pre tabindex="0"') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't seem that "dirty" to me.
Co-authored-by: gabalafou <[email protected]>
I think this PR is in a good shape to merge and has been approved so will go ahead and merge 🚀 there is one question from Dan somewhere but it is non-blocking at all |
only fail is codecov; in it goes! thanks @gabalafou |
#1787) One of many fixes for the failing accessibility tests (see #1428). The accessibility tests were still reporting some violations of: - Scrollable region must have keyboard access (https://dequeuniversity.com/rules/axe/4.8/scrollable-region-focusable) even after merging #1636 and #1777. These were due to Jupyter notebook outputs that have scrollable content. This PR extends the functionality of PRs #1636 and #1777 to such outputs. - Adds a test for tabindex = 0 on notebook outputs after page load This also addresses one of the issues in #1740: missing horizontal scrollbar by: - Adding CSS rule to allow scrolling - Add ipywidgets example to the examples/pydata page
* Ensure code blocks (<pre>) are keyboard focusable * Also cover <pre> tags not covered by starttag * Update src/pydata_sphinx_theme/translator.py Co-authored-by: gabalafou <[email protected]> --------- Co-authored-by: Tania Allard <[email protected]>
pydata#1787) One of many fixes for the failing accessibility tests (see pydata#1428). The accessibility tests were still reporting some violations of: - Scrollable region must have keyboard access (https://dequeuniversity.com/rules/axe/4.8/scrollable-region-focusable) even after merging pydata#1636 and pydata#1777. These were due to Jupyter notebook outputs that have scrollable content. This PR extends the functionality of PRs pydata#1636 and pydata#1777 to such outputs. - Adds a test for tabindex = 0 on notebook outputs after page load This also addresses one of the issues in pydata#1740: missing horizontal scrollbar by: - Adding CSS rule to allow scrolling - Add ipywidgets example to the examples/pydata page
Fixes #1100.
Also closes one of the subtasks of #1428.
Inspired by #1104.
Whitespace-preserving blocks in our theme, such as code blocks, currently do not have an easy way for keyboard users to focus on them and use the arrow keys to scroll the block to the right in order to read long lines that overflow the width of the block. This is also an accessibility issue; if you have to use a mouse, a pointer, or your finger—anything other than just your keyboard—to scroll a code block, then that's a violation of WCAG 2.1.1.
Check the end user effects of this PR on the Read the Docs preview build of the Kitchen Sink Blocks page