Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
cdax opened this issue Nov 26, 2018 · 24 comments
Labels
issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet issue/has-pr Issue has a PR attached to it that may solve the issue issue/reviewed Issue has recently been reviewed (mid-2020)

Comments

@cdax
Copy link

cdax commented Nov 26, 2018

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
Copy link

vtaits commented Dec 24, 2018

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
Copy link

Mawaheb commented Jan 8, 2019

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
Copy link

jdt3969 commented Feb 5, 2019

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

@kaiz-rently
Copy link

Any updates on this one ?

@M-Yankov
Copy link

M-Yankov commented Jun 20, 2019

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

@bladey bladey added the issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet label May 29, 2020
@bladey bladey added the issue/reviewed Issue has recently been reviewed (mid-2020) label Jun 17, 2020
@bladey bladey added the issue/has-pr Issue has a PR attached to it that may solve the issue label Jul 6, 2020
@ebonow ebonow linked a pull request Mar 12, 2021 that will close this issue
@OS-rafaelduarte
Copy link

OS-rafaelduarte commented Dec 28, 2021

Any updates on this? @ebonow

@Duarte10
Copy link

Duarte10 commented Dec 28, 2021

Created PR #4970 to fix this issue.

@faraazHasan
Copy link

Please merge #4970 to fix this issue.

@imranisdev
Copy link

HI Please can we get thie MR merged. That you

@jacobsickels
Copy link

jacobsickels commented May 11, 2023

Bumping for visibility, please merge the above MR

@jannnik
Copy link

jannnik commented Nov 29, 2023

We are also waiting for this fix!

@AbdullahPS
Copy link

Another one who is wating :(

@malininss
Copy link

Why is this PR #4970 are still not merged? 3 year have passed, fix contains few minor changes. Are there any contributors?

@khachatryna
Copy link

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

@DavidSentiurin
Copy link

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

I am also waiting for this fix.

@amaralpeek
Copy link

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
Copy link

malininss commented Jun 18, 2024

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
Copy link

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
Copy link

malininss commented Jun 20, 2024

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
Copy link

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
Copy link

samdark commented Aug 16, 2024

We're affected by it as well. @JedWatson is it possible to review/merge #4970?

1 similar comment
@mKlus
Copy link

mKlus commented Aug 29, 2024

We're affected by it as well. @JedWatson is it possible to review/merge #4970?

@SairamAlagapan
Copy link

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

@GilTorch
Copy link

GilTorch commented Jan 21, 2025

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

;

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

const onScrollToBottomTrigger = useInfiniteScroll(customOnMenuScrollToBottom);

return (
<components.MenuList<SelectOption, false, GroupBase>
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

;
};
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

I tried this implementation and the only issue I'm having is that it constantly calls the customOnMenuScrollToBottom prop when you scroll down. I'm looking for a way to fix that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue/bug-unconfirmed Issues that describe a bug that hasn't been confirmed by a maintainer yet issue/has-pr Issue has a PR attached to it that may solve the issue issue/reviewed Issue has recently been reviewed (mid-2020)
Projects
None yet