Skip to content
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

Make focus visible (mostly CSS) #13415

Merged
merged 3 commits into from
Dec 6, 2022

Conversation

gabalafou
Copy link
Contributor

@gabalafou gabalafou commented Nov 14, 2022

References

I'm not sure there is a single issue that corresponds to this PR, but it's related to:

Code changes

The biggest change introduced by this PR is that I delete the bit of CSS that disables the browser's default focus-visible indicator. This is a major accessibility anti-pattern.

After restoring the focus-visible outline, I went about fixing parts of the UI that that change messed up.

I also search-replaced the CSS, replacing border with outline for focus-visible. For several reasons, outline is a better choice.

User-facing changes

Every element that can receive focus should now have a visible outline. The following videos show screen casts of me pressing the tab key in JupyterLab. Each element that receives focus has a visible indicator.

Safari

Screen.Recording.2022-11-14.at.16.01.20.mov

Chrome

Screen.Recording.2022-11-14.at.16.02.44.mov

Firefox

Screen.Recording.2022-11-14.at.16.03.28.mov

Backwards-incompatible changes

The only potentially backward-incompatible change is where I remove the tabindex attribute from the main area widget. All the other changes are just style tweaks.

@jupyterlab-probot
Copy link

Thanks for making a pull request to jupyterlab!
To try out this branch on binder, follow this link: Binder

Copy link
Contributor Author

@gabalafou gabalafou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done self-reviewing.

@@ -36,13 +36,6 @@ a:hover {
color: unset;
}

/* Disable default focus outline */
:focus {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a risk that this exposes the focus-visible indicator in ways that some users find ugly. But I would prefer to have an ugly focus-visible indicator that prompts aesthetic interventions from users and contributors rather than take away a key accessibility feature from users that need it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabalafou this changes the settingseditor's input:focus appearance, replacing the light blue gradient with a strong dark blue, similar to the following diff (new on left):

Was that expected or just a consequence ?
I'm asking this to know if I should open a PR to fix this for the settingseditor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that was not specifically intended. Sorry about that! (If you're short on time, just let me know, and I can submit a PR to fix that. I'm quite familiar now with configuring focus states in CSS, so it shouldn't take me much time.)

By the way, do you know why I cannot tab-key to the drop-downs in the settings editor?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I had already something about that. I opened #13554.

By the way, do you know why I cannot tab-key to the drop-downs in the settings editor?

No idea, it seems to work on my end, if you mean reaching a drop-down with tab-key.

@@ -67,7 +67,6 @@ export class MainAreaWidget<T extends Widget = Widget>
if (!content.id) {
content.id = DOMUtils.createDomID();
}
content.node.tabIndex = 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marthacryan could you take a look at this change?

After playing for some time with the JupyterLab UI, I couldn't find any good reason to give the main area widget a tab index. Every main area widget that I could find has some element within it that can receive focus, so there's no reason that I can think of to make the container receive focus. I thought maybe it had to do with widgets that only have content and no editing functions (like contextual help). I thought maybe putting a tab index on the container would help the user to use page up and page down keyboard keys to scroll the content, but in fact (on my Mac at least), when the container element has focus I cannot use the page up and page down keys to scroll.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why the visual tests fail (and updates cannot be generated https://github.com/jupyterlab/jupyterlab/actions/runs/3503291407). Since all other changes are CSS-only, my suspicion is that galata may depend on MainAreaWidget being focusable. This is usually required in order to receive keyboard events. Could we try with

content.node.tabIndex = -1;

?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gabalafou I opened gabalafou#12. In particular tests hang on:

await tab.click();
await this.page.waitForFunction(
({ tab }) => {
return tab.classList.contains('jp-mod-current');
},
{ tab }
);

and this is visible in the UI as the tabs do not get the blue highlight the way they used to:

focus-problem

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry thought I responded here! If you can't find a good reason to set that tabindex to 0 that's totally fine to remove. I went through and tried to remove a bunch of tabindex being set to -1 and I may have been setting them to 0 for no good reason. Thanks for working on this!

Comment on lines +41 to +58
.lm-MenuBar-content:focus-visible {
outline-offset: -3px; /* this value is a compromise between Firefox, Chrome,
and Safari over this outline's visibility and discretion */
}

.lm-MenuBar:focus-visible {
outline: 1px solid var(--jp-accept-color-active, var(--jp-brand-color1));
outline-offset: -1px;
}

.lm-MenuBar-menu:focus-visible,
.lm-MenuBar-item:focus-visible,
.lm-Menu-item:focus-visible {
outline: unset;
outline-offset: unset;
-moz-outline-radius: unset;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the changes here, the tabbing/focus user experience for the Lumino menubar is not great. The menubar UX needs to be changed at the Lumino level. But my intention with this PR is not to fix all keyboard navigation issues. My intention with this PR is to make focus visible. There are elements that shouldn't receive focus but do, and vice versa. But even if the tabbing order or the set of elements that can receive focus doesn't make sense, that's not a reason to hide the focus indicator; it's a reason to fix which elements receive focus and in which order. At least that's how I see it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this changes be applicable to lumino too therefore be better included as default lumino styles?

The menubar UX needs to be changed at the Lumino level.

Does jupyterlab/lumino#465 address the changes needed? Would you be able to help reviewing it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh neat! I'll take a look at that PR today, thanks @krassowski!

The problem with the Lumino menubar is that it renders an HTML structure like this:

<div tabindex="0">
  <div tabindex="0">
    <ul>
      <li tabindex="0">

So the user has to tab through an outer container, then an inner container, and then finally each item in the menu bar (File, Edit, etc.). I think that ideally the menubar component should output a single DOM node with tabindex=0 so that the end user can navigate to the menubar, and then from there use arrow keys to access the different parts of the menubar. I'm hoping that's what jupyterlab/lumino#465 does.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea of simplifying the DOM output of menubar as it could help with performance too.

@gabalafou gabalafou changed the title Fix focus visible (mostly CSS) Make focus visible (mostly CSS) Nov 14, 2022
@krassowski
Copy link
Member

This surfaces an issue with the file browser ignoring focused elements. I think that we would either need to rewrite file browser listing to use browser focus (may be hard), or make the items unfocusable and handle it all programatically (as we currently do).

Actually since the file browser listing can have 100s of files, those should probably be only focused (regardless of implementation detail) only after explicit user confirmation. The alternative is adding a skip-link. I think that the former would be better UX.

@gabalafou
Copy link
Contributor Author

@krassowski thanks! You are 100% spot on. My intention was to roll out a number of follow-up PRs to this one that address some of the issues that this PR surfaces (such as the file browser ignoring focussed elements). I wanted to keep this PR fairly small and focussed on making focus visible, separate from any other issues around focus. But do you think I should update this PR to address some of these other issues instead of doing it in a separate PR?

For the file browser in particular, my preference would be to make it possible for the user to tab to the directory listing, but then remove the ability to tab to individual files within the list. Instead the user would just use the arrow keys, which is already supported, whereas pressing the tab key would move the user away from the directory listing to another part of the JupyterLab UI. What do you think? Should I go ahead and make that change in this PR or in a follow-up?

@krassowski
Copy link
Member

I like your plan for the file browser listing. I am happy to approve it as-is (though let's ensure the UI tests pass) as it is already an improvement.

No strong preference for a single large PR vs multiple smaller ones, especially if you are targeting 4.0.

@krassowski
Copy link
Member

bot please update snapshots

1 similar comment
@fcollonval
Copy link
Member

bot please update snapshots

@krassowski krassowski modified the milestones: 4.0.0, 3.6.0 Nov 28, 2022
@krassowski
Copy link
Member

I took liberty of switching milestone as I would love to see this in 3.6.

gabalafou#12 should solve the visual testing regression (which is relevant).

@krassowski
Copy link
Member

bot please update snapshots

@krassowski
Copy link
Member

The documentation code needs updating to ensure there is no focus on irrelevant elements as that will confuse the documentation readers. It would also be nice if this PR did not change the dimensions of buttons (as seen on the popup dialog galata documentation screenshot)

@fcollonval
Copy link
Member

In c5339c5, I updated the documentation test to remove noisy focus highlight for documentation snapshot. I did not modify the sizing change for the button as actually this fixes the jitter of the button switching to having a 0 border to 1px border when focus due to CSS rules like:

@fcollonval fcollonval merged commit e658b6f into jupyterlab:master Dec 6, 2022
@fcollonval
Copy link
Member

@meeseeksdev please backport to 3.6.x

@lumberbot-app
Copy link

lumberbot-app bot commented Dec 6, 2022

Owee, I'm MrMeeseeks, Look at me.

There seem to be a conflict, please backport manually. Here are approximate instructions:

  1. Checkout backport branch and update it.
git checkout 3.6.x
git pull
  1. Cherry pick the first parent branch of the this PR on top of the older branch:
git cherry-pick -x -m1 e658b6f28e3501968e7fe8e211677c5378be14d0
  1. You will likely have some merge/cherry-pick conflict here, fix them and commit:
git commit -am 'Backport PR #13415: Make focus visible (mostly CSS)'
  1. Push to a named branch:
git push YOURFORK 3.6.x:auto-backport-of-pr-13415-on-3.6.x
  1. Create a PR against branch 3.6.x, I would have named this PR:

"Backport PR #13415 on branch 3.6.x (Make focus visible (mostly CSS))"

And apply the correct labels and milestones.

Congratulations — you did some good work! Hopefully your backport PR will be tested by the continuous integration and merged soon!

Remember to remove the Still Needs Manual Backport label once the PR gets merged.

If these instructions are inaccurate, feel free to suggest an improvement.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants