Accessibility: A JupyterLab Developer’s Guide#
If you’re making changes to the JupyterLab source code and you’re concernedaboutaccessibility, this pageis for you.
Looking for other ways tocontribute to accessibility on Jupyter projects?
Where to start#
Thank you for being interested in improving JupyterLab’s accessibility. Whethermaking accessibility-specific fixes or considering the accessibility impacts ofanother contribution, your work betters JupyterLab for everyone who uses it.
A common question when accessibility-minded developers come to JupyterLab is:where do I get started?
If you don’t have a lot of time to immerse yourself in the big picture ofJupyterLab accessibility work, then the GitHub issues labeledgood first issueand accessibilityare a good place to start.
If you want to more fully immerse yourself in the work of making JupyterLab (orother Jupyter projects) more accessible, then a good place to start would be tojoin theJupyter accessibility meetingthat happens every other week. If you cannot attend the call, you can peruse themeeting notes and find links to other resources on theJupyter Accessibility site.
Looking for afrontend developer’s orientation to the JupyterLab codebase?
Best practices while developing#
JupyterLab is a web application and authoring tool. Therefore the followingstandards apply:
These are good places to familiarize yourself with accessibility best practicesfor developing websites (WCAG) and web applications (ARIA). Note that althoughWCAG was created primarily for static websites, the guidelines are nonethelessapplicable to web apps like JupyterLab.
One resource that is often particularly helpful for developers looking forexamples and best practices isARIA Patterns. This web resource containsexamples of how to implement UI elements—such as menus, dialogs, breadcrumbs,and more—in a more accessible way. However, be careful! Just because you canimplement a button using divs and aria attributes does not mean that you should!(Most likely you should just use the button tag.) As a best practice, you shouldonly use ARIA when you cannot use existing HTML elements (button, input, nav,aside, etc.) to achieve the UX that you desire.
Finally, there is much more accessibility knowledge on the Internet than thereis in JupyterLab or Project Jupyter alone. Whatever you decide to work on,consider exploring accessibility resources in other spaces for similar orequivalent efforts. Accessibility communities tend to be generous with theresources they provide to improve web accessibility. Many times, searching forthe name of the task or issue appended withaccessibility in a search enginewill give you several results and a chance to learn from the broader communityright away.
The rest of this section contains best practices specific to JupyterLab and itsdevelopment.
Use color variables from the CSS#
When fixing contrast or other visual accessibility issues in JupyterLab, it canbe tempting to pick a color and apply it to the part of the UI that you areworking on. However, it quickly becomes unmanageable to have color values spreadthroughout the app across different CSS files. Therefore, the JupyterLabcodebase defines a set ofcolor variablesthat can be used for borders, icons, and such. If you’re adding any CSS thatneeds a color value, please use one of the variables defined.
Upstream fixes in Lumino#
JupyterLab uses a front-end framework that was built specifically for it calledLumino. Lumino is similar in some ways to React, Vue, and Angular, but it alsoprovides a number of UI widgets like menu bars, tab bars, and dock panels. As aresult, some of the accessibility issues reported in the JupyterLab GitHub reponeed to be fixed in the Lumino repo. A good resource for learning Lumino:PhosphorJS (now Lumino) Mentor Sessions.PhosphorJS was Lumino’s previous name. There is a page withnotes from thePhosphorJS sessions thatalso has a link to some additional videos that were not uploaded to YouTube.
It’s not always obvious when an accessibility issue should be fixed inJupyterLab or Lumino. Some guidance to help you identify where your changeshould be made:
Generally speaking, if you can fix the issue in Lumino, it’s better to fix itin Lumino because then the fix will be absorbed in more places.
However, for that same reason, because Lumino is used by more codebases thanjust JupyterLab—specifically, by JupyterLab extensions—one should be carefulmaking changes to Lumino that might break downstream consumers/extensions.
So an additional rule of thumb is: if you can’t make the fix in Lumino withoutbreaking dependants, then it might be better to make the fix in JupyterLab. Inthis case, you might take a two-track approach, where you fix theaccessibility issue in JupyterLab and also submit a breaking fix in Luminothat targets a future, major, API-breaking release/version of Lumino.
Automated Regression Testing#
If you fix an accessibility issue in the source code but you don’t add a testwith your fix, then there’s a strong chance that your fix will be undoneaccidentally by some future changes to the codebase.
Sometimes it’s straightforward to unit-test an accessibility fix, such as whenenabling keyboard shortcuts on a toolbar button. But often it’sdifficult to unit-test accessibility fixes.
Therefore there is an effort underway to usePlaywright to write user-levelaccessibility tests toJupyterLab.To illustrate how to use it within your development process, let’s walk throughan example.
This example will involve three separate GitHub repos:
This is a real world example, taken from actual past work.
Let’s say you do an accessibility audit of the start page of the JupyterLab UIand find a tab trap in the top menu bar, meaning the user can press the tab keyto get into the menu bar but cannot easily get past it using only the keyboard.
You dig in further and discover that thetab trap bug is in thejupyterlab/lumino repo, soyou fork the jupyterlab/lumino repo, create a new branch calledfix-tab-trap, and open a pull request.
You decide that you want to write a test. This is one of those cases where writing a unit test would be a straightforward task. However, a unit test would only check thetop menu bar, so it would not prevent a reappearance of the issue that youdecided you want to fix once and for all, namely: you don’t want any tab trapsanywhere on the JupyterLab start page.
So you decide that you want toadd a regression test to theQuansight-Labs/jupyter-a11y-testing repo.This test checks that there are no tab traps on the JupyterLab start page byusing Playwright to open JupyterLab and press the tab key repeatedly. So as withthe Lumino repo before, you fork the Quansight-Labs/jupyter-a11y-testing repo,create a branch calledtest-tab-trap, and open a pull request. The importantthing in this step is that you save your test file with a.test.ts extensionnext to the other regression test files.
Now you want to run your test. Specifically, you want to run the test against abuild of JupyterLab that incorporates your Lumino fix. Here’s how you would dothat.
Let’s pretend that your GitHub username isa11ydev and you’ve forked theLumino and testing repos and created the following branches on those forks, onewith your bug fix and the other with your test:
a11ydev/lumino:fix-tab-trapa11ydev/jupyter-a11y-testing:test-tab-trap
On GitHub, go to your fork of the testing repo,a11ydev/jupyter-a11y-testing.Make sure that you are on yourtest-tab-trap branch, which contains the.test.ts file that you added. Then go to Actions and click on the workflowtitled “Run accessibility tests on JupyterLab.” Click “Run workflow.” This willopen a form to configure the workflow.
Here’s how you should fill out the form:
Use workflow from:
test-tab-trapJupyterLab repo:
jupyterlab/jupyterlabBranch/tag/SHA:
mainTest suite: leave blank
External package repo:
a11ydev/luminoExternal package ref:
fix-tab-trap
Then press the “Run workflow” button. A GitHub action should then buildJupyterLab from source, linking your Lumino fork and branch, then run the testsuite, including your test, and then finally show the test results, hopefullywith your test passing.
Note that in this example you did not fork the jupyterlab/jupyterlab repo orchange the branch name to something other than “main” in the workflow configform. This is because you did not need to modify the JupyterLab codebase to fix this issue. But if you were working on an issue that required youto modify the JupyterLab codebase, you would do the same thing that you didearlier with Lumino: fork the repo, create a branch with your fix, and thenenter your fork and branch in the workflow config form before running theworkflow. That should cause it to build a version of JupyterLab based on yourchanges and then run the test suite against it. The workflow is flexible enoughto allow you to test against changes in JupyterLab or Lumino or both at the sametime if needed.
Note
There are moredetailed instructions for how to use the GitHub workflow in the testing repo.
PR Review and Manual Testing#
When reviewing code, documentation, or other contributions, you can use manualtesting to help prevent accessibility bugs. Typically you try and complete atask related to your fix or contribution using an accessibility accommodation orsetting. Common options include:
Using ascreen reader.
Zooming the page up to 400% via your browser.
Unplugging or not using your mouse. Navigate only with the keyboard.
Emulating vision deficiencies(Chrome, Edge, and Firefox all provide built-in tools to do this.)
While testing, take note of what happens and compare it to what you can do tocomplete the task without your chosen accessibility accommodation. If there isanything you cannot complete, then you have a blocking accessibility issue. Eventhough your use of assistive tech or an accessibility accommodation will likelydiffer from someone who uses them regularly, knowing the results is helpful totell if JupyterLab is behaving as you expect.
Useful tools for development#
Here is a list of some apps that developers have found useful while doingaccessibility work in JupyterLab:
Chrome Dev Tools fordiscovering and fixing low contrast text andforviewing the accessibility tree
Axe DevTools,extension for Chrome Dev Tools
Color Contrast Analyzer,desktop app for Windows and Mac
Polypane, desktop browser with some dev toolsbuilt in (note it’s not free but it does have a free trial)
Axe Accessibility Linter,extension for VS Code
And of course, screen readers such as JAWS, NVDA, and VoiceOver.