material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

[a11y] Not keyboard accessible for components inside `MenuItem`

Open ber8749 opened this issue 3 years ago • 8 comments

Duplicates

  • [X] I have searched the existing issues

Latest version

  • [X] I have tested the latest version

Steps to reproduce 🕹

Link to live example: https://codesandbox.io/s/beautiful-voice-bfgjc9

Steps:

  1. Tab into menu and hit the "Enter" button
  2. Hit the "down arrow" button until you arrive at the slider/switch
  3. Hit "Enter"/"Space" button(s) to focus on slider/switch

Current behavior 😯

The slider/switch will not focus, preventing users from manipulating the input with their keyboard.

Expected behavior 🤔

The slider/switch should focus, allowing users to manipulate the input with their keyboard.

Context 🔦

Allow our keyboard users to manipulate menu input.

Your environment 🌎

npx @mui/envinfo
   System:
    OS: macOS 12.6.1
  Binaries:
    Node: 14.18.3 - ~/.nvm/versions/node/v14.18.3/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v14.18.3/bin/yarn
    npm: 8.1.2 - ~/Projects/vt-llp-ui/node_modules/.bin/npm
  Browsers:
    Chrome: 107.0.5304.121 <= current browser
    Edge: Not Found
    Firefox: 107.0
    Safari: 16.1
  npmPackages:
    @emotion/react: 11.10.0 => 11.10.0 
    @emotion/styled: 11.10.0 => 11.10.0 
    @mui/base:  5.0.0-alpha.94 
    @mui/core-downloads-tracker:  5.10.13 
    @mui/material: 5.10.2 => 5.10.2 
    @mui/private-theming:  5.10.9 
    @mui/styled-engine:  5.10.8 
    @mui/system:  5.10.13 
    @mui/types:  7.2.0 
    @mui/utils:  5.10.9 
    @types/react: 17.0.38 => 17.0.38 
    react: 17.0.2 => 17.0.2 
    react-dom: 17.0.2 => 17.0.2 
    typescript: 4.6.4 => 4.6.4 

ber8749 avatar Nov 29 '22 22:11 ber8749

Thanks for reporting this. It's a similar issue to what's described in https://github.com/mui/material-ui/issues/33268. We'll look into supporting such scenarios in MUI Base's Menu (which will be used by the Material UI's one in the future).

If, however, someone from the community would like to take a stab at fixing it in the current version of Material UI, I'm happy to discuss it and review a PR.

michaldudak avatar Nov 30 '22 11:11 michaldudak

@ber8749 i'm not sure if it's possible to focus elements inside MenuItem natively by library, but there is a workaround to focus Switch element inside MenuItem

 <MenuItem onFocus={(e) => ref.current.focus()}>
          <Switch inputRef={ref} defaultChecked />
        </MenuItem>

sai6855 avatar Dec 03 '22 13:12 sai6855

Thanks for reporting this. It's a similar issue to what's described in #33268. We'll look into supporting such scenarios in MUI Base's Menu (which will be used by the Material UI's one in the future).

If, however, someone from the community would like to take a stab at fixing it in the current version of Material UI, I'm happy to discuss it and review a PR.

@michaldudak i did some digging, as far as i understood it's not possible to automatically detect which element user want to focus with exsisting props. So i'm thinking a new prop transferFocusTo which accepts dom element, can be passed to MenuItem might solve the issue, so when ever MenuItem is focused if that MenuItem also has transferFocusTo prop, we will focus element passed in transferFocusTo prop too

This might be how Api look .

Api:

        <MenuItem transferFocusTo={ref.current}>
          <Switch defaultChecked inputRef={ref} />
        </MenuItem>

Implementation:

      <MenuItemRoot
        ref={handleRef}
        role={role}
        onFocus={(e) => {
          if (transferFocusTo) {
            transferFocusTo.focus();
          }

          handleFocus(e);
        }}
        tabIndex={tabIndex}
        component={component}
        focusVisibleClassName={clsx(classes.focusVisible, focusVisibleClassName)}
        className={clsx(classes.root, className)}
        {...other}
        ownerState={ownerState}
        classes={classes}
      />

If you are fine with proposal i'm happy to create PR

sai6855 avatar Dec 03 '22 18:12 sai6855

After discussing it internally with the team and reading through ARIA specs, I started to think it may not be the best idea to allow all interactive elements within menus. Sliders, for example, are controlled by arrow keys and will interrupt the normal flow of highlighting menu items when focused. Sliders with multiple thumbs present an even more significant challenge.

Switches, on the other hand, should present no such problems. ARIA defines the menuitemcheckbox role (https://w3c.github.io/aria/#menuitemcheckbox), which we could use here. So technically, it will be a checkbox, but it could be styled as a switch. We can create a MenuItemCheckbox component with such functionality.

michaldudak avatar Dec 05 '22 11:12 michaldudak

@ber8749 i'm not sure if it's possible to focus elements inside MenuItem natively by library, but there is a workaround to focus Switch element inside MenuItem

 <MenuItem onFocus={(e) => ref.current.focus()}>
          <Switch inputRef={ref} defaultChecked />
        </MenuItem>

@sai6855 Thank you, this was quite helpful. Do you know of a similar workaround for the Slider component?

ber8749 avatar Dec 06 '22 20:12 ber8749

@ber8749

    <MenuItem onFocus={() => ref.current.focus()}>
          <Slider slotProps={{ input: { ref } }} aria-label="Volume" />
        </MenuItem>

sai6855 avatar Dec 07 '22 04:12 sai6855

@ber8749 i'm not sure if it's possible to focus elements inside MenuItem natively by library, but there is a workaround to focus Switch element inside MenuItem

This solution makes the menu inaccessible. For example, the arrow keys do not work correctly.

michaldudak avatar Dec 07 '22 10:12 michaldudak

Relevant discussion on the W3C github:

  • https://github.com/w3c/aria/issues/1587

xurxe avatar Dec 12 '22 14:12 xurxe