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

File browser items in focus state draw a rectangle around the itemText node, which disappears when hovering on any menu #14678

Closed
ibdafna opened this issue Jun 13, 2023 · 18 comments · Fixed by #15860

Comments

@ibdafna
Copy link
Member

ibdafna commented Jun 13, 2023

Description

File browser items in focus state draw a rectangle around the itemText node, which disappears when hovering on any menu

Reproduce

Select any item in the file browser and then hover over the top menu, or right click on the currently selected file. See attached gif.

jlab4x-selection-bug

Expected behavior

Two behaviors I'd expect:

  1. I understand the reasoning behind responding to the focus state in the file browser (Make file browser respond to focussed elements #13577), but perhaps there is a better way of indicating focus than drawing this rectangle around the object.
  2. The logic appears inconsistent when hovering on menus. Does hover indicate focus? I would argue it does not unless the menu item is clicked on. If hovering does indicate focus, then hovering over other files in the browser, which are currently not selected or clicked on, should follow the same logic as hovering over menu items.

Context

  • Operating System and version: MacOS
  • Browser and version: Chrome/Edge 114.0.5735.106
  • JupyterLab version: 4.0.2
@ColinConwell
Copy link

Any updates on this design feature? Can the behavior be reverted easily to jupyter 3.6.3 style behavior?

@krassowski
Copy link
Member

krassowski commented Oct 7, 2023

perhaps there is a better way of indicating focus than drawing this rectangle around the object

GNOME file browser uses a subtle border colour change to differentiate focused from selected. The slight challenge here is that we also have checkboxes (hidden by default) so I guess this is why it is not an outline over the entire item but only over the file name. I do agree that this is suboptimal and a bit distracting. Suggestions welcome!

@ColinConwell
Copy link

ColinConwell commented Oct 7, 2023

Hmmm. I think at least my aesthetic issue could be resolved effectively with a css override that removes the outline properties from jupyter/packages/style/base.css? Or maybe I'm not quite getting the subtleties here?

.jp-DirListing-itemText:focus {
    outline-width: 2px;
    outline-color: var(--jp-inverse-layout-color1);
    outline-style: solid;
    outline-offset: 1px;
  }

.jp-DirListing-item.jp-mod-selected .jp-DirListing-itemText:focus {
    outline-color: var(--jp-layout-color1);
  }

@ColinConwell
Copy link

ColinConwell commented Oct 8, 2023

I got rid of this by running a manual override in my web environment. Would there be a way to inject this when loading jupyterlab? Maybe in the ServerApp.extra_static_paths = [] config?

function overrideStyles() {
  var sheets = document.styleSheets;
  for (var i = 0; i < sheets.length; i++) {
    var rules = sheets[i].cssRules || sheets[i].rules;
    for (var j = 0; j < rules.length; j++) {
      var rule = rules[j];
      if (rule.selectorText === ".jp-DirListing-itemText:focus" ||
          rule.selectorText === ".jp-DirListing-item.jp-mod-selected .jp-DirListing-itemText:focus") {
        rule.style.setProperty('outline-width', '0', 'important');
      }
    }
  }
}

@mlucool
Copy link
Contributor

mlucool commented Oct 23, 2023

I agree this state is confusing by default. This almost matches the Windows edit state which is what I thought I got into by accident

image

@krassowski
Copy link
Member

Together with a duplicate issue we got 6 reports that the current behaviour is annoying. I think that in the first instance we should change :focus to :focus-visible in this section:

.jp-DirListing-itemText:focus {
outline-width: 2px;
outline-color: var(--jp-inverse-layout-color1);
outline-style: solid;
outline-offset: 1px;
}
.jp-DirListing-item.jp-mod-selected .jp-DirListing-itemText:focus {
outline-color: var(--jp-layout-color1);
}

so that the browser auto-hides it when its heuristics show it is not relevant. CC @gabalafou as the author of #13577 and accessibility expert.

@krassowski
Copy link
Member

Some possibilities for a different focus indicator are discussed in https://themesbycarolina.com/indicating-focus-without-outline/, one of which is using underline - it could look like:

image

@krassowski
Copy link
Member

It also looks like the checkboxes are not accessible using keyboard at all. If we made the items togglable by Space, but kept Enter as-is to open the file, we could move the focus indicator from the file name to the entire entry (using :focus-within), either with black outer ring or white internal ring:

Black external White internal
image image

@mlucool
Copy link
Contributor

mlucool commented Feb 14, 2024

FWIW, I find the checkmark confusing. I like the "one of which is using underline" option best.

@gabalafou
Copy link
Contributor

I appreciate people looking into this.

I would like to make a number of points to hopefully get us all on the same page.

The current state of things

  • The point in the PR description about menu hover stealing focus away from the file browser (expected behavior no. 2) has been fixed. (Refer to MenuBar: do not focus on hover lumino#607.) I verified this in JupyterLab version 4.1.1.
  • The checkboxes not being keyboard accessible is news to me. I can confirm this is broken in v4.1.1. There must have been a regression somewhere between my PR #13577 and 4.1.1.

Guiding principle

As a guiding principle: a user should always be able to answer the question "which element on the page has focus?" in order for the site to meet the Web Content Accessibility Guidelines (refer to Understanding Success Criterion SC 2.4.7).

Constraints to consider

  • Many sites use :focus-visible to meet 2.4.7 for keyboard-only users while leaving mouse and touch users unaffected, but using that selector in JupyterLab leads to UX behavior that I deem irregular or unexpected. The reason why is that JupyterLab does a lot of internal focus management, and my hunch is that this messes up the browser's own heuristics for when to show the focus ring (for example, calling focus on mousedown). This leaves us with three options if we want sensical focus behavior: (1) use :focus, not :focus-visible, in other words, don't rely on the browser's heuristics and always show the focus ring when focussed; (2) refactor and offload some of JupyterLab's focus management to the browser, so that the browser's :focus-visible heuristics lead to expected behavior; or (3) do not rely on the browser at all, forego the CSS :focus and :focus-visible pseudo-selectors, and rely on our own heuristics, not the browser's. Of those three options, the first one is the easiest to implement, minimizing the risk of breaking existing functionality.
  • Focus can move independently of selection in the file browser. "Selection" indicates that you have selected some number of files to perform some action on them. "Focus" indicates where the browser focus (document.activeElement) is. Multiple files can be selected; only one file can be focussed (because only one DOM element in the browser can be focussed at a time). The selection state is indicated by a dark blue background color (#1976D2). The focus state is indicated by a solid outline around the file name (black when file is not selected, white otherwise). The point here is that because "focus" and "selection" are two independent but possibly overlapping states, it's not possible to unambiguously distinguish the independent from the overlapping states using color—unless we were to try to combine the colors in some exotic way, like with a gradient, and even then the two colors would have to be carefully chosen to have sufficient contrast. So it would be better to use some other kind of visual indicator like the ones discussed in the blog post that Mike linked in an earlier comment.

Question

@krassowski could you elaborate on this comment you made from before?

The slight challenge here is that we also have checkboxes (hidden by default) so I guess this is why it is not an outline over the entire item but only over the file name. I do agree that this is suboptimal and a bit distracting.

My two cents

I am in favor of moving forward with one of the designs that Mike put forward, using one of those as a focus ring that always appears on focus, whether via keyboard or mouse (in other words, applying the focus indicator with :focus or :focus-within instead of :focus-visible).

@krassowski
Copy link
Member

could you elaborate on this comment you made from before?

The slight challenge here is that we also have checkboxes (hidden by default) so I guess this is why it is not an outline over the entire item but only over the file name. I do agree that this is suboptimal and a bit distracting.

My assumption was that the reason the focus ring was put around the file name rather than around the entire item was because user may need to distinguish between checkbox being focused and the item being focused.

@krassowski
Copy link
Member

Thanks @gabalafou!

Focus can move independently of selection in the file browser. "Selection" indicates that you have selected some number of files to perform some action on them.

This is a good point.
Worth noting that selection has something called a head which is what indicates the active element in selection.

The point here is that because "focus" and "selection" are two independent but possibly overlapping states, it's not possible to unambiguously distinguish the independent from the overlapping states using color

Selection head and focus can be indicated with the same visual when element is focused, so as as an alternative we could use a hue+lightness combination:

focused: "a", "b", "c" selected, "c" is the head (and focused) blurred: "a", "b", "c" selected, "c" is the head
image image

The downside is that distinction between blue and grey (e.g. #1565c0 vs #616161) is not necessarily accessible for some very rare kinds of colourblindness (achromatopsia and partially for tritanopia, in total about 8 in 10 000 people).

The reason why is that JupyterLab does a lot of internal focus management, and my hunch is that this messes up the browser's own heuristics for when to show the focus ring (for example, calling focus on mousedown).

I do not see it this way. I think that using :focus-visible does lead to a better behaviour and browser heuristic is absolutely right; taking the GIFs from PR switching to :focus-visible (#15802):

Before After
focus-always no-focus-ring-on-click

I believe it is expected NOT to show the focus ring when focusing an element with mousedown because if I am a user and clicked on an element with a mouse I do know which element is becoming focused because I just clicked on it ; on the other hand if I switched focus using Tab key it may have landed me on the active browser item and I might not immediately know that so I would want to see the focus ring.

Can you point to a more specific argument against switching to :focus-visible by demonstrating an unexpected focus behaviour on the file browser in a major browser? If there is such then of course lets not do it, but I did not see any in my testing.

There must have been a regression somewhere between my PR #13577 and 4.1.1.

Probably worth adding tests for it then.

@gabalafou
Copy link
Contributor

user may need to distinguish between checkbox being focused and the item being focused.

Nope, no need to distinguish so long as we make sure that the space bar can be used to select a file and that the checked state of the checkbox matches the selected state of the file.

we could use a hue+lightness combination

For the reasons you pointed out and others, it's considered bad practice to visually indicate semantically distinct states through the use of color alone.

But I also think there's another problem here. How are we to communicate when a file is focussed but not selected? Imagine the user has selected file A, B, and the selection head is on C. So A and B are colored light blue, and C dark blue. But now the user wants to add file E to the selection and has to step over file D. Our user can only use a keyboard. So they press control + down arrow to move focus to (but not select) D and press control + down arrow again to move the focus to E. Then they add E to the selection by pressing the space bar. So now A, B, and C should be colored light blue. E should be dark blue I guess. But how should we have indicated focus earlier on D and E before E was selected? If we use light gray then I think that makes the use of gray ambiguous since as I understand it, gray is meant to indicate to the user that there are files selected in the file browser but that the focus is somewhere outside the file browser.

I think that using :focus-visible does lead to a better behaviour and browser heuristic is absolutely right

It's possible that the confusing behavior that I observed when I was implementing #13577 (and originally wanted to use :focus-visible rather than :focus) has disappeared with intervening changes to either JupyterLab or to browsers, since they're always changing. I'll try to find some time to give your PR (#15802) a look and see if :focus-visible still misbehaves.

I think somehow you may have gotten the opposite of the point that I was trying to make with my Codepen. I totally agree with you that a focus ring should not be shown on mousedown. And if you leave focus management up to the browser, that's what you generally get. But, as my Codepen demonstrates, you can get weird behavior from the browser if you call .focus() from within a mousedown handler. My Codepen demonstrates that the browser will draw a :focus-visible ring around an element when it's clicked even if the user has not pressed a single key on their keyboard, and that's not what should happen. When I was working on #13577, I encountered weird behavior of that sort (but maybe not that exact, specific mousedown-focus-ring behavior) and that's why I opted for :focus over :focus-visible (if I remember correctly).

The other reason I opted for :focus over :focus-visible is that the focussed item is one of the endpoints of the multi-select operation, and it's therefore useful for the mouse user, too, to see which element has focus (though perhaps a better solution would be to have the focus ring appear when the user presses the control, command, or shift key, which is what the browser does, I think, with :focus-visible—so it would be great if we can get :focus-visible to work right within the JupyterLab file browser. I'm all for that.

Probably worth adding tests for it then.

Agreed. I will try to find some time this week to figure out and hopefully fix and test what broke.

@gabalafou
Copy link
Contributor

I created an issue about the file browser checkboxes and assigned myself #15819

@krassowski
Copy link
Member

we could use a hue+lightness combination

For the reasons you pointed out and others, it's considered bad practice to visually indicate semantically distinct states through the use of color alone.

The guidelines you link to specifically allows for use of hue+lightness though:

If content is conveyed through the use of colors that differ not only in their hue, but that also have a significant difference in lightness, then this counts as an additional visual distinction [...]

My mockup was not great with this respect but we could make the blurred state use lighter greys and dark text; further we could solve the blue vs grey limitation on that front by having an additional indicator on file listing level (focus-within).

But I also think there's another problem here. How are we to communicate when a file is focussed but not selected? Imagine the user has selected file A, B, and the selection head is on C. So A and B are colored light blue, and C dark blue. But now the user wants to add file E to the selection and has to step over file D. Our user can only use a keyboard. So they press control + down arrow to move focus to (but not select) D and press control + down arrow again to move the focus to E.

Discontinuous selections 🎉 Yeah, I forgot about this. Let's have a think:

abc selected, c is the head and focused abc selected, d is focused but not selected blurred: abc selected, "c" is the head
image image image

This seems to check all the boxes, even for achromatopsia.

@gabalafou
Copy link
Contributor

The guidelines you link to specifically allows for use of hue+lightness though

Right. I wasn't clear but I was referring specifically to your mockups and even more specifically to the fact that color (more specifically, hue) was being relied on too heavily to distinguish the left mockup from the right.

But the newest set of mocks don't have that problem, so we are both on the same page here! 😃

I'm really liking this newest set of mockups. One thing I'm wondering though... if the user moves the (blue) focus ring into the selected area (by pressing control + up arrow), does the ring disappear and become a darker shade of blue to represent the selection head? Or does it become a white focus ring?

To put my cards on the table, I'm a little concerned about changing how we indicate focus with respect to how we indicate selection. I think it's fine to make the focus ring surround the entire file instead of just the file name, and to change its color. I think it's also fine to try to get :focus-visible to work properly so that the focus ring only shows up when the user is relying on the keyboard. But any other changes to how we indicate focus might have unforeseen consequences. More concretely, I'm recommending that we stick to indicating focus with a focus ring and not try to indicate it some other way.

I say that because I spent many, many hours playing with keyboard-only file selection across different operating systems, and I learned that it's very tricky to get it to behave in ways that feel consistent and intuitive. For example, a naive implementation of a file browser would say that whenever the user holds down shift and presses the arrow key, then add to the selection. But operating systems use a more complicated rule, which is that shift + arrow adds to the selection unless the user is shift-arrowing into an already selected region of files and coming from an unselected region. When you throw discontinuous groups of selected files into the mix and the user shift-arrows across them, you quickly find yourself with questions about UI state transitions that don't have clear and obvious answers.

What I'm saying is that I spent a very long time and was very careful about the way I implemented the file browser focus ring given the existing way to visually indicate selection. We can certainly try to create new and better ways to do this, but be warned: as they say, here be dragons.

@krassowski
Copy link
Member

I'm recommending that we stick to indicating focus with a focus ring and not try to indicate it some other way

Is this an accurate representation of the current consensus plan moving forward?

  • use :focus-visible (or emulate it if there is a problem with default heuristics, but it has not been demonstrated)
  • keep ring indicator, but move it from file name to the entire item (possibly making it nicer with rounded corners/different colour)
  • consider if we can re-use suggested improvements to selection styling from my comment above in the future but not as a direct solution because the focus ring is staying

@krassowski
Copy link
Member

#15860 is ready for review.

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

Successfully merging a pull request may close this issue.

6 participants