Skip to content

Commit d3f6357

Browse files
committed
Fix keyboard access for scrollable regions created by notebook outputs
1 parent cdde445 commit d3f6357

File tree

2 files changed

+32
-5
lines changed

2 files changed

+32
-5
lines changed

src/pydata_sphinx_theme/assets/scripts/pydata-sphinx-theme.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -693,10 +693,11 @@ function setupMobileSidebarKeyboardHandlers() {
693693
}
694694

695695
/**
696-
* When the page loads or the window resizes check code blocks and Jupyter
697-
* notebook outputs, and if they have scrollable overflow, set tabIndex = 0.
696+
* When the page loads, or the window resizes, or descendant nodes are added or
697+
* removed from the main element, check all code blocks and Jupyter notebook
698+
* outputs, and for each one that has scrollable overflow, set tabIndex = 0.
698699
*/
699-
function setupLiteralBlockTabStops() {
700+
function addTabStopsToScrollableElements() {
700701
const updateTabStops = () => {
701702
document
702703
.querySelectorAll(
@@ -712,7 +713,25 @@ function setupLiteralBlockTabStops() {
712713
: -1;
713714
});
714715
};
715-
window.addEventListener("resize", debounce(updateTabStops, 300));
716+
const debouncedUpdateTabStops = debounce(updateTabStops, 300);
717+
718+
// On window resize
719+
window.addEventListener("resize", debouncedUpdateTabStops);
720+
721+
// The following MutationObserver is for ipywidgets, which take some time to
722+
// finish loading and rendering on the page (so even after the "load" event is
723+
// fired, they still have not finished rendering). Would be nice to replace
724+
// the MutationObserver if there is a way to hook into the ipywidgets code to
725+
// know when it is done.
726+
const mainObserver = new MutationObserver(debouncedUpdateTabStops);
727+
728+
// On descendant nodes added/removed from main element
729+
mainObserver.observe(document.getElementById("main-content"), {
730+
subtree: true,
731+
childList: true,
732+
});
733+
734+
// On page load
716735
updateTabStops();
717736
}
718737
function debounce(callback, wait) {
@@ -736,4 +755,7 @@ documentReady(setupSearchButtons);
736755
documentReady(initRTDObserver);
737756
documentReady(setupMobileSidebarKeyboardHandlers);
738757
documentReady(fixMoreLinksInMobileSidebar);
739-
documentReady(setupLiteralBlockTabStops);
758+
759+
// Use load event because determining whether an element has scrollable content
760+
// depends on stylesheets (which come after DOMContentLoaded)
761+
window.addEventListener("load", addTabStopsToScrollableElements);

src/pydata_sphinx_theme/assets/styles/extensions/_notebooks.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
html div.rendered_html,
1313
// NBsphinx ipywidgets output selector
1414
html .jp-RenderedHTMLCommon {
15+
// Add some margin around the element box for the focus ring. Otherwise the
16+
// focus ring gets clipped because the containing elements have `overflow:
17+
// hidden` applied to them (via the `.lm-Widget` selector)
18+
margin: $focus-ring-width;
19+
1520
table {
1621
table-layout: auto;
1722
}

0 commit comments

Comments
 (0)