JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.63k stars 4.13k forks source link

onMenuScrollToBottom not fired on desktop when the scrollbar is mouse-dragged to the bottom #3232

Open cdax opened 5 years ago

cdax commented 5 years ago

Greetings!

Thank you so much for taking time out to maintain react-select

One of our users reported that the dropdowns in our product (the ones powered by react-select) were not loading further options when she scrolled to the bottom. On further investigation, we realized that this was because react-select does not fire onMenuScrollToBottom when the scrolling is performed by dragging the scrollbar to the bottom using a mouse-drag. Unfortunately for us and for this user, her mouse lacks a scroll wheel and so this is the only way she can scroll to the bottom.

Here's a code sandbox demonstrating this issue: https://codesandbox.io/s/x20ppz92xw Note that when scrolled using the mousewheel, an alert dialog is displayed when the menu is scrolled to the bottom. However, when the scrollbar is dragged to the bottom using the mouse, the alert dialog isn't displayed.

Looking at the source code, I can see that the ScrollCaptor is only listening for the wheel, touchstart and touchmove events. The use-case of dragging the scrollbar with a mouse is ignored.

I've confirmed that this works in the previous major version (v1.2.1)

vtaits commented 5 years ago

I understood that onMenuScrollToBottom is weakness of react-select. It also not working with keyboard navigation and for asynchronous select. My workaround is redefine MenuList component.

https://github.com/vtaits/react-select-async-paginate/blob/master/src/wrap-menu-list.jsx

It is my decorator, but is uses custom handler handleScrolledToBottom, you can replace it with onMenuScrollToBottom. Looped setTimeout is not beautiful but works.

Mawaheb commented 5 years ago

any updates on this one? I am having the same issue, I am relying on onMenuScrollToBottom to fetch and append paginated values to a drop down, it won't work if the user used keyboard or scrollbar dragging :/.

jdt3969 commented 5 years ago

Also looking for an update. This seems like a core bug and necessary for accessibility

kaiz-rently commented 5 years ago

Any updates on this one ?

M-Yankov commented 5 years ago

I understood that onMenuScrollToBottom is weakness of react-select. It also not working with keyboard navigation and for asynchronous select. My workaround is redefine MenuList component.

https://github.com/vtaits/react-select-async-paginate/blob/master/src/wrap-menu-list.jsx

It is my decorator, but is uses custom handler handleScrolledToBottom, you can replace it with onMenuScrollToBottom. Looped setTimeout is not beautiful but works.

Here is the correct link of the wrapper ~https://github.com/vtaits/react-select-async-paginate/blob/master/packages/react-select-async-paginate/src/wrap-menu-list.jsx~ https://github.com/vtaits/react-select-async-paginate/blob/master/packages/react-select-async-paginate/src/wrapMenuList.tsx

OS-rafaelduarte commented 2 years ago

Any updates on this? @ebonow

Duarte10 commented 2 years ago

Created PR https://github.com/JedWatson/react-select/pull/4970 to fix this issue.

faraazHasan commented 1 year ago

Please merge https://github.com/JedWatson/react-select/pull/4970 to fix this issue.

imranisdev commented 1 year ago

HI Please can we get thie MR merged. That you

jacobsickels commented 1 year ago

Bumping for visibility, please merge the above MR

jannnik commented 11 months ago

We are also waiting for this fix!

AbdullahPS commented 11 months ago

Another one who is wating :(

malininss commented 8 months ago

Why is this PR https://github.com/JedWatson/react-select/pull/4970 are still not merged? 3 year have passed, fix contains few minor changes. Are there any contributors?

khachatryna commented 6 months ago

I've set captureMenuScroll property true and it works on my side.

DavidSentiurin commented 5 months ago

Thank you for the helpful select library and your work, guys!

I am also waiting for this fix.

amaralpeek commented 4 months ago

Any update on this issue? It still doesn't work, even with khachatryna suggestion to use captureMenuScroll.

Does anyone have a workaround for this problem?

malininss commented 4 months ago

Does anyone have a workaround for this problem?

I've created a custom onMenuScrollToBottom function as a workaround in my project.

Firstly, we need to declare new prop type for our select. Lets create file react-select.d.ts:

import { Props } from 'react-select/dist/declarations/src/Select';

declare module 'react-select/dist/declarations/src/Select' {
  export interface Props {
    customOnMenuScrollToBottom?: () => void;
  }
}

Now you can pass this custom prop to the ReactSelect component. Also you need to create custom MenuList component and pass it to ReactSelect too:

import { YoutCustomMenuListComponent } from './components/YoutCustomMenuListComponent';

<ReactSelect
  customOnMenuScrollToBottom={() => {
    console.log('scrollToBottom');
  }}
  components={{
    MenuList: YourCustomMenuListComponent,
  }}
....

Now lets create a YourCustomMenuListComponent:

import { SelectOption } from '../../type'; // Your select option type.

type YourCustomMenuListComponentProps = ReactSelectMenuListProps<
  SelectOption,
  false,
  GroupBase<SelectOption>
>;

export const YourCustomMenuListComponent = ({
  children,
  ...rest
}: YourCustomMenuListComponentProps) => {
  const { customOnMenuScrollToBottom } = rest.selectProps;

  const onScrollToBottomTrigger = useInfiniteScroll(customOnMenuScrollToBottom);

  return (
    <components.MenuList<SelectOption, false, GroupBase<SelectOption>>
      className={styles.menuList}
      {...rest}
    >
      {children}
      {customOnMenuScrollToBottom && onScrollToBottomTrigger}
    </components.MenuList>
  );
};

And useInfiniteScroll is a pretty standard hook which uses Intersection Observer, like this:

export const useInfiniteScroll = (callback?: () => void): JSX.Element => {
  const observerRef = useRef<IntersectionObserver | null>(null);
  const lastElementRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    if (!callback) {
      return undefined;
    }

    if (lastElementRef.current) {
      observerRef.current = new IntersectionObserver((entries) => {
        if (entries[0].isIntersecting) {
          callback();
        }
      });
      observerRef.current.observe(lastElementRef.current);
    }

    return () => {
      if (observerRef.current) {
        observerRef.current.disconnect();
        observerRef.current = null;
      }
    };
  }, [callback]);

  return <div ref={lastElementRef} />;
};

We are finished. The callback customOnMenuScrollToBottom will be triggered each time when we scroll to the bottom of the component. I created an infinity scroll with data fetching inside the Select component based on this solution. Hope it helps someone

amaralpeek commented 4 months ago
import { Props } from 'react-select/dist/declarations/src/Select';

declare module 'react-select/dist/declarations/src/Select' {
  export interface Props {
    customOnMenuScrollToBottom?: () => void;
  }
}

Hey malininss thanks for the solution it will do for now, it works and does the job. This is something that should be in the component, but anyway I appreciate your help!

malininss commented 4 months ago

This is something that should be in the component

Hi @amaralpeek. Do you mean that we are supposed to place this declaration inside the Select component? If yes, I prefer to place all declarations (such as this third party lib interface extension) in a separate file with a d.ts postfix. It is more transparent because this types are used not only inside the component, but also in other parts of the application.

Maybe I didn't get you right. Anyway, it depends on your coding style and can be done in different ways

amaralpeek commented 4 months ago

Hey malininss, Sorry for the confusion, When I reply I used the "Quote Reply" and the final part was related to the react-select package which should be a fixed part of the component, nothing related with your solution and thanks again for that!

samdark commented 2 months ago

We're affected by it as well. @JedWatson is it possible to review/merge https://github.com/JedWatson/react-select/pull/4970?

mKlus commented 2 months ago

We're affected by it as well. @JedWatson is it possible to review/merge https://github.com/JedWatson/react-select/pull/4970?

SairamAlagapan commented 1 week ago

@JedWatson Is it possible to review/merge #4970 ?