react-select icon indicating copy to clipboard operation
react-select copied to clipboard

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

Open cdax opened this issue 6 years ago • 22 comments

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)

cdax avatar Nov 26 '18 13:11 cdax

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.

vtaits avatar Dec 24 '18 14:12 vtaits

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 :/.

Mawaheb avatar Jan 08 '19 11:01 Mawaheb

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

jdt3969 avatar Feb 05 '19 04:02 jdt3969

Any updates on this one ?

kaiz-rently avatar May 16 '19 06:05 kaiz-rently

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

M-Yankov avatar Jun 20 '19 07:06 M-Yankov

Any updates on this? @ebonow

OS-rafaelduarte avatar Dec 28 '21 13:12 OS-rafaelduarte

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

Duarte10 avatar Dec 28 '21 17:12 Duarte10

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

faraazHasan avatar Jan 19 '23 10:01 faraazHasan

HI Please can we get thie MR merged. That you

imranisdev avatar Mar 24 '23 17:03 imranisdev

Bumping for visibility, please merge the above MR

jacobsickels avatar May 11 '23 13:05 jacobsickels

We are also waiting for this fix!

jannnik avatar Nov 29 '23 17:11 jannnik

Another one who is wating :(

AbdullahPS avatar Nov 30 '23 21:11 AbdullahPS

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?

malininss avatar Feb 29 '24 04:02 malininss

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

khachatryna avatar May 10 '24 15:05 khachatryna

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

I am also waiting for this fix.

DavidSentiurin avatar Jun 05 '24 09:06 DavidSentiurin

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?

amaralpeek avatar Jun 18 '24 10:06 amaralpeek

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

malininss avatar Jun 18 '24 12:06 malininss

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!

amaralpeek avatar Jun 19 '24 13:06 amaralpeek

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

malininss avatar Jun 20 '24 02:06 malininss

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!

amaralpeek avatar Jun 25 '24 17:06 amaralpeek

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

samdark avatar Aug 16 '24 15:08 samdark

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

mKlus avatar Aug 29 '24 04:08 mKlus