downshift icon indicating copy to clipboard operation
downshift copied to clipboard

BUG Selecting dropdown item does nothing when input is off screen

Open sean0x42 opened this issue 4 years ago • 3 comments

  • downshift version: 6.1.7
  • node version: 16.13.2
  • npm (or yarn) version: 8.1.2

Relevant code or config

This is a near identical copy+paste from the useCombobox docs. Just modified styles slightly and then added an extra element to the bottom of the page to force scrolling.

Click to expand code snippet
import React, { useState } from 'react'
import { useCombobox } from 'downshift'

const items = [
  'Apples',
  'Applesaft',
  'Apple juice',
  'Apple pie',
  'Apple jam',
  'Apple sauce',
];

const menuStyles = {
  listStyleType: "none",
  margin: 0,
  padding: 0
}

const baseItemStyles = {
  padding: '10px'
}

function DropdownCombobox() {
  const [inputItems, setInputItems] = useState(items)

  const {
    isOpen,
    getToggleButtonProps,
    getLabelProps,
    getMenuProps,
    getInputProps,
    getComboboxProps,
    highlightedIndex,
    getItemProps,
  } = useCombobox({
    items: inputItems,
    onInputValueChange: ({ inputValue }) => {
      setInputItems(
        items.filter(item =>
          item.toLowerCase().startsWith(inputValue.toLowerCase()),
        ),
      )
    },
  })

  return (
    <div>
      <label {...getLabelProps()}>Choose an apple:</label>
      <div {...getComboboxProps()}>
        <input {...getInputProps()} />
        <button
          type="button"
          {...getToggleButtonProps()}
          aria-label="toggle menu"
        >
          &#8595;
        </button>
      </div>
      <ul {...getMenuProps()} style={menuStyles}>
        {isOpen &&
          inputItems.map((item, index) => (
            <li
              style={
                highlightedIndex === index
                  ? { ...baseItemStyles, backgroundColor: '#bde4ff' }
                  : { ...baseItemStyles }
              }
              key={`${item}${index}`}
              {...getItemProps({ item, index })}
            >
              {item}
            </li>
          ))}
      </ul>

      <p style={{ marginTop: '50rem' }}>Some extra content to make sure the viewport is scrollable.</p>
    </div>
  )
}

export default DropdownCombobox

What you did:

Using Android Chrome (occasionally seems to repro on MacOS Chrome also)

Simply scroll the page so that the dropdown menu is still visible, but the input no longer is. Tap a result, and nothing will happen.

What happened:

This video shows the end result best:

https://user-images.githubusercontent.com/9998591/151899519-70206077-75f3-4884-bd62-d6a68cd87b58.mp4

When this issue occurs, there is an __item_mouse_moved__ event, but no click event: image

Compare that to what happens when you don't scroll the input out of view: image

Reproduction repository:

See pages/index.js for example function, and run npm run dev to spin up Next.js dev server. https://github.com/sean0x42/downshift-focus-bug-repro

Problem description:

Suggested solution:

I have absolutely no idea. I did some digging, but I'm guessing there is a race condition somewhere. If you put a breakpoint anywhere, this appears to resolve the issue. So it's like something timing related that the extra breakpoint slows down the execution enough to resolve.

sean0x42 avatar Feb 01 '22 01:02 sean0x42

Hi, I'm not able to reproduce this in a PC using Device Emulation. It works normally regardless of how far the input has been scrolled. Perhaps this is a problem only on mobile devices?

Go1dExperience avatar Mar 01 '22 13:03 Go1dExperience

Hi, I'm not able to reproduce this in a PC using Device Emulation. It works normally regardless of how far the input has been scrolled. Perhaps this is a problem only on mobile devices?

It definitely could be. I was testing on a Pixel 4 running Chrome for Android. My coworker could not repro on iOS.

I might be able to get that repro running on GitHub pages, and then it would be easy for anyone to test on mobile. Would that be helpful?

sean0x42 avatar Mar 01 '22 20:03 sean0x42

Some browsers attempt to scroll elements into the viewport when they are focused, my guess is that this is what is happening here.

This line runs the input.focus() method when an item is clicked and without the preventScroll option for the focus method then the browser should scroll it into view.

aaronnuu avatar Mar 02 '22 08:03 aaronnuu

We are not doing the input.focus() anymore in that handler anymore since v7. If the bug persists, please open a new ticket. Thank you!

silviuaavram avatar Dec 17 '22 15:12 silviuaavram