downshift icon indicating copy to clipboard operation
downshift copied to clipboard

Disabled items are highlighted when select is opened with Arrow Up/Down

Open Eldraed opened this issue 3 years ago • 1 comments

  • downshift version: 6.1.3
  • node version: 14.17.3
  • npm (or yarn) version: npm 6.14.13

Relevant code or config

Example taken from my reproduction :

<ul {...getMenuProps()} style={menuStyles}>
  {isOpen &&
    items.map((item, index) => (
      <li
        style={{
          ...(highlightedIndex === index
            ? {backgroundColor: '#bde4ff'}
            : {}),
          // First and last elements are disabled
          ...(index === 0 || index === items.length - 1
            ? {opacity: 0.6}
            : {}),
        }}
        key={`${item}${index}`}
        {...getItemProps({
          item,
          index,
          disabled: index === 0 || index === items.length - 1,
        })}
      >
        {item}
      </li>
    ))}
</ul>

I just consider that my first and last elements in my list are disabled.

What you did: I have a list of items with some of them disabled. I want to navigate through my enabled items only with keyboard.

What happened: With useSelect (the only one i use): When i use my keyboard for navigation, with focus on my Toggle button, if i press Arrow up/down to open the list, first or last element will be highlighted even if it's disabled.

HighlightOnDisabled

  • First, i just open it with my mouse, we can see that the first and last items can't be highlighted
  • Then, i open it with Arrow down, first item is highlighted, even if it's disabled
  • Same with Arrow up and last item

Reproduction repository:

Here is where i have recorded the video : https://codesandbox.io/s/snowy-cloud-t5zyw?file=/src/hooks/useSelect/basic-usage.js It's a fork of Downshift examples with changes to reproduce on useSelect basic usage example.

Problem description:

Disabled elements should not be highlighted on menu opening with arrow keys

Suggested solution:

The reducer here : https://github.com/downshift-js/downshift/blob/master/src/hooks/useSelect/reducer.js#L42-L63 is using getHighlightedIndexOnOpen to know which item to highlight on menu opening. But it returns 0 or items.length - 1 if it doesn't fit with initial, default and selectedItem values : https://github.com/downshift-js/downshift/blob/master/src/hooks/utils.js#L304

Maybe this return should be improved to use getNextNonDisabledIndex here : https://github.com/downshift-js/downshift/blob/master/src/utils.js#L368-L407 ? As it's currently done with MenuKeyDownArrowDown/MenuKeyDownArrowUp and getNextWrappingIndex that use getNextNonDisabledIndex : https://github.com/downshift-js/downshift/blob/master/src/utils.js#L343-L355

Hope the problem is understood, let me know if it's not 🙂

Eldraed avatar Jul 28 '21 13:07 Eldraed

I'm having this issue as well, exactly like you describe.

While it doesn't fix the highlighting issue, at least you can avoid the disabled item being selected by giving Downshift a state reducer that looks like this:

useSelect({
  stateReducer: (state, actionAndChanges) => {
    // If the item to be selected is disabled, don't select it.
    if (actionAndChanges.changes.selectedItem?.disabled) {
      return { ...actionAndChanges.changes, selectedItem: state.selectedItem };
    }

    return actionAndChanges.changes;
  }
})

This code snippet relies on having a disabled property on your items. If you don't, then you will have to figure out if the soon-to-be-selected item is disabled or not some other way.

tobiasthorin avatar Apr 26 '22 13:04 tobiasthorin

Duplicate of https://github.com/downshift-js/downshift/issues/1176. Will track it there.

silviuaavram avatar Dec 17 '22 14:12 silviuaavram