docs/source/developer/accessibility.md
% Copyright (c) Jupyter Development Team.
% Distributed under the terms of the Modified BSD License.
If you're making changes to the JupyterLab source code and you're concerned about accessibility, this page is for you.
Looking for other ways to contribute to accessibility on Jupyter projects?
Thank you for being interested in improving JupyterLab's accessibility. Whether making accessibility-specific fixes or considering the accessibility impacts of another 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 of JupyterLab accessibility work, then the GitHub issues labeled good first issue and accessibility are a good place to start.
If you want to more fully immerse yourself in the work of making JupyterLab (or other Jupyter projects) more accessible, then a good place to start would be to join the Jupyter accessibility meeting that happens every other week. If you cannot attend the call, you can peruse the meeting notes and find links to other resources on the Jupyter Accessibility site.
Looking for a frontend developer's orientation to the JupyterLab codebase?
JupyterLab is a web application and authoring tool. Therefore the following standards apply:
These are good places to familiarize yourself with accessibility best practices for developing websites (WCAG) and web applications (ARIA). Note that although WCAG was created primarily for static websites, the guidelines are nonetheless applicable to web apps like JupyterLab.
One resource that is often particularly helpful for developers looking for examples and best practices is ARIA Patterns. This web resource contains examples of how to implement UI elements—such as menus, dialogs, breadcrumbs, and more—in a more accessible way. However, be careful! Just because you can implement 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 should only 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 there
is in JupyterLab or Project Jupyter alone. Whatever you decide to work on,
consider exploring accessibility resources in other spaces for similar or
equivalent efforts. Accessibility communities tend to be generous with the
resources they provide to improve web accessibility. Many times, searching for
the name of the task or issue appended with accessibility in a search engine
will give you several results and a chance to learn from the broader community
right away.
The rest of this section contains best practices specific to JupyterLab and its development.
When fixing contrast or other visual accessibility issues in JupyterLab, it can be tempting to pick a color and apply it to the part of the UI that you are working on. However, it quickly becomes unmanageable to have color values spread throughout the app across different CSS files. Therefore, the JupyterLab codebase defines a set of color variables that can be used for borders, icons, and such. If you're adding any CSS that needs a color value, please use one of the variables defined.
JupyterLab uses a front-end framework that was built specifically for it called Lumino. Lumino is similar in some ways to React, Vue, and Angular, but it also provides a number of UI widgets like menu bars, tab bars, and dock panels. As a result, some of the accessibility issues reported in the JupyterLab GitHub repo need 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 with notes from the PhosphorJS sessions that also 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 in JupyterLab or Lumino. Some guidance to help you identify where your change should be made:
If you fix an accessibility issue in the source code but you don't add a test with your fix, then there's a strong chance that your fix will be undone accidentally by some future changes to the codebase.
Sometimes it's straightforward to unit-test an accessibility fix, such as when enabling keyboard shortcuts on a toolbar button. But often it's difficult to unit-test accessibility fixes.
Therefore there is an effort underway to use Playwright to write user-level accessibility tests to JupyterLab. To illustrate how to use it within your development process, let's walk through an 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 UI and find a tab trap in the top menu bar, meaning the user can press the tab key to get into the menu bar but cannot easily get past it using only the keyboard.
You dig in further and discover that the tab trap bug is in the
jupyterlab/lumino repo, so
you fork the jupyterlab/lumino repo, create a new branch called
fix-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 the top menu bar, so it would not prevent a reappearance of the issue that you decided you want to fix once and for all, namely: you don't want any tab traps anywhere on the JupyterLab start page.
So you decide that you want to add a regression test to the
Quansight-Labs/jupyter-a11y-testing repo.
This test checks that there are no tab traps on the JupyterLab start page by
using Playwright to open JupyterLab and press the tab key repeatedly. So as with
the Lumino repo before, you fork the Quansight-Labs/jupyter-a11y-testing repo,
create a branch called test-tab-trap, and open a pull request. The important
thing in this step is that you save your test file with a .test.ts extension
next to the other regression test files.
Now you want to run your test. Specifically, you want to run the test against a build of JupyterLab that incorporates your Lumino fix. Here's how you would do that.
Let's pretend that your GitHub username is a11ydev and you've forked the Lumino and testing repos and created the following branches on those forks, one with your bug fix and the other with your test:
a11ydev/lumino:fix-tab-trapa11ydev/jupyter-a11y-testing:test-tab-trapOn GitHub, go to your fork of the testing repo, a11ydev/jupyter-a11y-testing.
Make sure that you are on your test-tab-trap branch, which contains the
.test.ts file that you added. Then go to Actions and click on the workflow
titled "Run accessibility tests on JupyterLab." Click "Run workflow." This will
open a form to configure the workflow.
Here's how you should fill out the form:
test-tab-trapjupyterlab/jupyterlabmaina11ydev/luminofix-tab-trapThen press the "Run workflow" button. A GitHub action should then build JupyterLab from source, linking your Lumino fork and branch, then run the test suite, including your test, and then finally show the test results, hopefully with your test passing.
Note that in this example you did not fork the jupyterlab/jupyterlab repo or change the branch name to something other than "main" in the workflow config form. 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 you to modify the JupyterLab codebase, you would do the same thing that you did earlier with Lumino: fork the repo, create a branch with your fix, and then enter your fork and branch in the workflow config form before running the workflow. That should cause it to build a version of JupyterLab based on your changes and then run the test suite against it. The workflow is flexible enough to allow you to test against changes in JupyterLab or Lumino or both at the same time if needed.
:::{note} There are more detailed instructions for how to use the GitHub workflow in the testing repo. :::
When reviewing code, documentation, or other contributions, you can use manual testing to help prevent accessibility bugs. Typically you try and complete a task related to your fix or contribution using an accessibility accommodation or setting. Common options include:
While testing, take note of what happens and compare it to what you can do to complete the task without your chosen accessibility accommodation. If there is anything you cannot complete, then you have a blocking accessibility issue. Even though your use of assistive tech or an accessibility accommodation will likely differ from someone who uses them regularly, knowing the results is helpful to tell if JupyterLab is behaving as you expect.
Here is a list of some apps that developers have found useful while doing accessibility work in JupyterLab: