Material-ui: [Menu] Improve hover/select/focus UI display

Created on 15 Sep 2016  路  18Comments  路  Source: mui-org/material-ui

Problem description

After initial open of menu, first item remains highlighted even after hovering off.

Steps to reproduce

next branch, menus demo http://localhost:3000/#/component-demos/menus

  1. click to open
  2. hover to a lower item

Versions

next branch a38068f90c28ee240f0622d40a87f6d888dd74e2

  • Browser: Mac Chrome 52.0.2743.116
  • Browser: Mac Firefox 48.0.2
  • Browser: Mac Safari 9.1.2

Images

fullscreen_9_15_16__10_21_am

bug 馃悰 Menu important material design

Most helpful comment

I would also be interested in an option to not have the first value selected. You may want a menu that performs actions and you never select an item. In order to get my desired effect, I have had to do the following:

<MenuItem key="placeholder" style={{display: "none"}} />

This is always the first item in the list so it gets highlighted but you don't see it cause it's hidden. Although this works, it is not ideal.

All 18 comments

@oliviertassinari Hi, sorry to be inactive for awhile!

Moving discussion from closed PR

I am not sure i understand Nathan...

Problem is with hover and different expexcted UX for touch and mouse devices. This way, when you open menu with something selected (first item is selected by default, but lets put this aside now), this remain selected until you click/touch another option. Alternatively, you can move your selected item with keyboard arrows.

Selected item has grey background. Hovered items also have grey background. So visually, you have 2 selected items when you move your mouse inside Menu (1 selected, 1 by hover). What should mouse hovering signify?
1) my proposal in rejected PR was to tie together hover and select states, which is quite radical solution. But it solves this dichotomy.
2) Both states could have different background color, and we will delete preselecting first option (keyboard actions with menu open will activate that though). This will solve problem with user perceiving 2 selected options.

Should i implement that 2) option?

@ArcanisCz I have been doing some benchmark, it's even worse than that. We have 3 possibles state. The focus, selected, and hover. You can have all of them at the same time:
capture d ecran 2017-07-16 a 19 14 59
Also, we should also consider where is the original focus, we focus the selected item or the first one

  • The native select input on chrome tie together the hover and select state but have a different style for the selected one:
    capture d ecran 2017-07-16 a 19 21 09

The selected item is focused by default, otherwise, the first one.

I think that the best option is to keep the default focus behavior and to change the style of the three possible different states. I like the react-bootstrap solution (same as bootrap@4-alpha).

I would also be interested in an option to not have the first value selected. You may want a menu that performs actions and you never select an item. In order to get my desired effect, I have had to do the following:

<MenuItem key="placeholder" style={{display: "none"}} />

This is always the first item in the list so it gets highlighted but you don't see it cause it's hidden. Although this works, it is not ideal.

I would really like to see this feature. Currently I'm using a <Popover> with a <List> to get around it, which is not really optimal.

Above work-around would also work, but is not ideal.

I think that the best option is to keep the default focus behavior and to change the style of the three possible different states.

In Google inbox, hover removes keyboard focus, so there is only ever one focused item. (Same as for Mac OS). For the Drawer list, they're using a slightly different shade for selected vs focus.

@mbrookes The "three state" approach seems quite common:

  • angular material2
    capture d ecran 2017-12-31 a 16 10 06
  • Vuetify
    capture d ecran 2017-12-31 a 16 09 56
  • Amazon
    capture d ecran 2017-12-31 a 16 00 13
  • Bootstrap v4
    capture d ecran 2017-12-31 a 16 12 42
  • material-web-components
    capture d ecran 2017-12-31 a 16 14 37

I'm going with this approach.

The final approach:

  1. disabled
  2. focus
  3. selected
  4. hover

capture d ecran 2018-06-21 a 17 13 20

The logic is no longer implemented, something has caused a regression, somewhere. We should take care of it. Also, it's a good opportunity to challenge what the best tradeoff is.

@oliviertassinari Do you have a reproduction I can look at? I'm not sure what I'm looking for :)

@joshwooding We have explored different approaches in https://github.com/mui-org/material-ui/pull/16331#issuecomment-504775954. What do you think of the approach n掳1?

@joshwooding We have explored different approaches in #16331 (comment). What do you think of the approach n掳1?

I want to double down on this quote:

We can challenge the need for these two states to have a different UI. I assume that most people use the mouse or the keyboard exclusively, rarely the two at the same time.

I completely agree here. One important part of a11y is that you consider focus(-visible) like any cursor. A sighted user can use the mouse to navigate to actions while screen reader users can use tab-focus. The focus outline marks the item that will be activated on-enter just like the hover marks the item that activates on mousedown. Enter and mousedown+up will both trigger a click event in the DOM. Styling hover and focus the same way is the only sensible thing if you think about it from a functional standpoint.

Since it's already hard enough to distinguish selected and focus I'd be perfectly fine with styling focus and hover the same way.

We can challenge the need for these two states to have a different UI. I assume that most people use the mouse or the keyboard exclusively, rarely the two at the same time.

@eps1lon Agree.


I have looked at the specification, I couldn't find any resources on the problem.
A new benchmark can help (selected, focused & hover states, in this order top-down):

Capture d鈥檈虂cran 2019-10-08 a虁 15 26 13
console.cloud.google.com

Capture d鈥檈虂cran 2019-10-08 a虁 15 28 02
studio.youtube.com (merge focus & hover)

Capture d鈥檈虂cran 2019-10-08 a虁 15 29 31
calendar.google.com (merge selected, focus & hover)

Capture d鈥檈虂cran 2019-10-08 a虁 15 34 10
ads.google.com (merge focus & hover)

Capture d鈥檈虂cran 2019-10-08 a虁 15 36 44
search.google.com (merge selected, focus & hover)


In this context, I would propose this fix:

diff --git a/packages/material-ui/src/ListItem/ListItem.js b/packages/material-ui/src/ListItem/ListItem.js
index d663d8934..9d11b30a3 100644
--- a/packages/material-ui/src/ListItem/ListItem.js
+++ b/packages/material-ui/src/ListItem/ListItem.js
@@ -23,7 +23,7 @@ export const styles = theme => ({
     paddingTop: 8,
     paddingBottom: 8,
     '&$focusVisible': {
-      backgroundColor: theme.palette.action.selected,
+      backgroundColor: theme.palette.action.hover,
     },
     '&$selected, &$selected:hover': {
       backgroundColor: theme.palette.action.selected,

We use to have this logic, it seems to have been lost (by mistake?) between #14680 and #14212. I'm not sure what I had in mind 馃. Would it work for you guys?

Also interesting that native <select /> makes no distinction at all between hover and selected. Once you hover over the first item the "highlight cursor" will follow hover. In keyboard modality it will follow focus. Both modalities have different behavior with regard to selection state (mouse: selection does not follow hover, keyboard: selection does follow focus).

Also interesting that native <select /> makes no distinction at all between hover and selected.

@eps1lon On which environment? On macOS, I have:

selected
Capture d鈥檈虂cran 2019-10-15 a虁 13 34 10

hover/focused
Capture d鈥檈虂cran 2019-10-15 a虁 13 34 16

Regarding the multi-select use case, the keyboard focus state needs to take precedence over the selected state, otherwise, you can't see where your focus is if you have, let's say 3 options selected consecutively.

I would propose a slightly different version to https://github.com/mui-org/material-ui/issues/5186#issuecomment-539525150

I like this tradeoff:

  • use the same style for hover/focus
  • keep the outline for keyboard focus to be visible when the item is selected
  • have the selected state to keep precedence over the hover/focus one.

What do you think?

diff --git a/packages/material-ui/src/ListItem/ListItem.js b/packages/material-ui/src/ListItem/ListItem.js
index d663d8934..dd03def41 100644
--- a/packages/material-ui/src/ListItem/ListItem.js
+++ b/packages/material-ui/src/ListItem/ListItem.js
@@ -23,7 +23,9 @@ export const styles = theme => ({
     paddingTop: 8,
     paddingBottom: 8,
     '&$focusVisible': {
-      backgroundColor: theme.palette.action.selected,
+      backgroundColor: theme.palette.action.hover,
+      outline: '2px solid #999',
+      outlineOffset: -2,
     },
     '&$selected, &$selected:hover': {
       backgroundColor: theme.palette.action.selected,

or

  • use the same style for hover/focus
  • have the hover/focus state to keep precedence over the selected one.
diff --git a/packages/material-ui/src/ListItem/ListItem.js b/packages/material-ui/src/ListItem/ListItem.js
index d663d8934..bf00ec1fe 100644
--- a/packages/material-ui/src/ListItem/ListItem.js
+++ b/packages/material-ui/src/ListItem/ListItem.js
@@ -22,11 +22,11 @@ export const styles = theme => ({
     textAlign: 'left',
     paddingTop: 8,
     paddingBottom: 8,
-    '&$focusVisible': {
+    '&$selected': {
       backgroundColor: theme.palette.action.selected,
     },
-    '&$selected, &$selected:hover': {
-      backgroundColor: theme.palette.action.selected,
+    '&$focusVisible': {
+      backgroundColor: theme.palette.action.hover,
     },
     '&$disabled': {
       opacity: 0.5,

What do you think?

I would need a render preview for that. Pure code is for UI/UX hard to review.

@eps1lon OK, I will open a pull request after #17037 is merged. The multi-select case adds constraints on the scope of the solutions available.

We might have a recommendation from the specification:

Capture d鈥檈虂cran 2020-01-21 a虁 12 04 18

Capture d鈥檈虂cran 2020-01-21 a虁 12 06 39

https://material.io/design/interaction/states.html#anatomy

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sys13 picture sys13  路  3Comments

ericraffin picture ericraffin  路  3Comments

ghost picture ghost  路  3Comments

ryanflorence picture ryanflorence  路  3Comments

TimoRuetten picture TimoRuetten  路  3Comments