Repository navigation
Fix keyboard navigation of tabsets in HTML documents without Bootstrap - #15007
Merged
Merged
Conversation
…730) HTML documents without Bootstrap (theme: none) use Quarto's copy of tabby (upstream cferdinandi/tabby v12.0.3). A 2021 patch made revealjs tabsets keyboard-usable by dropping the roving tabindex, activating tabs on focus, and limiting key handling to Home/End, so arrow keys stay with slide navigation. Only the positive tabindex numbering was scoped to revealjs; the rest applied to every tabby user. In HTML, Tab from the selected tab then lands on the next tab, selects it, and the panel content is unreachable. Outside revealjs, tabby now behaves as upstream again: only the selected tab is in the Tab order, arrow keys and Home/End switch tabs, and focus alone does not select a tab. revealjs keeps its current behavior. Handled keys now also call preventDefault: Firefox and WebKit otherwise scroll the page on Home/End (and arrow keys) while switching tabs. Bootstrap tabs do the same.
In revealjs, tabby selects the first or last tab on Home/End, but the keydown event kept propagating to reveal's own keyboard handler, which treats Home/End as "go to first/last slide". Selecting a tab from the keyboard therefore also navigated away from the slide holding the tabset. tabby listens on the tablist in the capture phase and reveal listens on the document, so stopping propagation once tabby has handled the key leaves reveal unaware of it. Outside revealjs, this also keeps the arrow keys and Home/End that switch tabs from reaching any other page-level keyboard handler, as with Bootstrap tabs.
Collaborator
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
In HTML documents without Bootstrap (
theme: none), tabsets use Quarto's copy of tabby. Pressing Tab on the selected tab moves focus to the next tab and selects it, so the content of the selected panel is never reachable from the keyboard. Arrow keys do nothing.Root cause
tabby.jsis upstream cferdinandi/tabby v12.0.3, which implements the WAI-ARIA tabs pattern (roving tabindex, arrow keys). A 2021 patch adapted it for revealjs, where arrow keys belong to slide navigation: every tab gottabindex="0", a tab became selected on focus, and key handling was limited to Home/End. Only the positive tabindex numbering was scoped to revealjs. The rest applied to every tabby user, includingtheme: noneHTML.Fix
Outside revealjs, tabby behaves as upstream again: only the selected tab is in the Tab order, arrow keys and Home/End switch tabs, and focus alone does not select a tab. This is the same behavior as Bootstrap tabs. revealjs keeps its current behavior; its focus order is discussed in #14970.
Handled keys now call
preventDefault()andstopPropagation(). WithoutpreventDefault(), Firefox and WebKit also scroll the page on Home/End. WithoutstopPropagation(), Home/End on a revealjs tab also reaches reveal's own keyboard handler, so it selects the tab and jumps to the first or last slide. That revealjs bug exists since the 2021 patch and is fixed here too.revealjs detection keeps the existing
body.reveal-viewportcheck rather thantypeof Reveal !== "undefined".Reveal.initialize()sets this class on the element whose keyboard input reveal drives, so it tells whether reveal owns the arrow keys on the page, while theRevealglobal only tells that the script was loaded. In Quarto's revealjs output both give the same answer, as tabsets are set up afterReveal.initialize().Fixes #730
Checklist
I have (if applicable):
AI-assisted PR
Note: autonomous AI agents submitting PRs without human oversight are not permitted — see the Code of Conduct.