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

Dropdown remains fixed in place and doesn't scroll with parent container #4088

Closed
bladey opened this issue Jun 15, 2020 · 62 comments · Fixed by #5256
Closed

Dropdown remains fixed in place and doesn't scroll with parent container #4088

bladey opened this issue Jun 15, 2020 · 62 comments · Fixed by #5256
Assignees
Labels
issue/bug-confirmed Issues about a bug that has been confirmed by a maintainer issue/reviewed Issue has recently been reviewed (mid-2020) menu-bug Addresses menu positioning, scrolling, or general interactions

Comments

@bladey
Copy link
Contributor

bladey commented Jun 15, 2020

This issue is a round-up of multiple past issues documenting the same bug. Feel free to check out the linked issues below for more information. This issue is the source of truth going forward to investigate the issue, report findings, and implement a bug fix.

Issue:

Screen Capture on 2020-06-15 at 14-43-03

Dropdown remains fixed in place and doesn't scroll with parent container.

The commit responsible for this issue is located here - 691a011

Version v3.0.4 does not have this bug however the latest release v3.1.0 does.

Issues:

#4554
#4020
#4052
#3734
#4085
#3929
#3349
#3646

Examples:

https://codesandbox.io/s/react-select-v3-sandbox-forked-lgkms
https://codesandbox.io/s/compassionate-cookies-85j2n
https://codesandbox.io/s/react-select-v3-sandbox-kr5wf
https://codesandbox.io/s/festive-dirac-izf5y
https://codesandbox.io/s/react-codesandboxer-example-xy47y

If anyone would like to share any further information, please do so.

@mjb95
Copy link

mjb95 commented Jun 15, 2020

Hi - for info, I have explicitly tested this by installing v3.0.4 and v3.0.3, and I experience the same issue in both versions. Is it possible that the bug existed even before the commit that you have highlighted above?

@palashkaria
Copy link

palashkaria commented Jun 25, 2020

I think @mjb95 is right, as this is the behaviour of React Select in v2 also; menuPosition fixed & portal, both do not update the positioning of the Menu on scroll - so the menu is stuck. All the sanboxes here have menuPosition fixed, and portal, and nothing related to it was changed in that commit.

The bug mentioned by @bladey is related to a workaround (menuShouldBlockScroll) to handle the issue of the menu not scrolling - as mentioned in this comment #3929 (comment).

This sandbox demonstrates that bug it better: on opening the menu, the scroll stops working completely.
https://codesandbox.io/s/elegant-sky-51tlo?file=/src/App.js

@bladey I suggest we separate these issues, as menuShouldBlockScroll is a completely separate issue, would not be fix this problem (& it should be done anyway).

This would only be solved if something like tether.js is pulled into the lib (which has been proposed before) #810 is directly related to this (and all others, except #3929), & has most of the problems/solutions related in one place - and IMO it is still not resolved. (see a hacky solution in this comment, which extends the Select class and uses react-tether + react-dimensions: #810 (comment))

@bladey bladey added issue/reviewed Issue has recently been reviewed (mid-2020) and removed issue/reviewed Issue has recently been reviewed (mid-2020) labels Jun 26, 2020
@srinivasmerugu
Copy link

Hi @bladey Could you please let us know if this would be prioritised and made available in next patch release please.

@bladey
Copy link
Contributor Author

bladey commented Jul 16, 2020

@srinivasmerugu we'll get to it as soon as we can, any updates will be provided here.

@bladey bladey closed this as completed Jul 16, 2020
@bladey bladey reopened this Jul 16, 2020
@mjb95
Copy link

mjb95 commented Jul 30, 2020

Hi, has any progress been made on this issue?

@bladey bladey added issue/reviewed Issue has recently been reviewed (mid-2020) and removed issue/reviewed Issue has recently been reviewed (mid-2020) labels Aug 24, 2020
@lohithvecham
Copy link

lohithvecham commented Sep 21, 2020

Hi, anyone has any update on this?
In my case, it's happening in the Chrome-75 version but not in 78 or 80 versions.

@HodayaGruz
Copy link

Hi, anyone has any update on this?
In my case, it's happening in the Chrome-75 version but not in 78 or 80 versions.

i see it happening in chrome 85.
when do you think it will fix?

@narojisivamurthi1230
Copy link

how much time it take to push this commit?

@Methuselah96
Copy link
Collaborator

Methuselah96 commented Nov 14, 2020

I've started a fork of react-select. Feel free to resubmit this issue on the fork and/or submit a PR to resolve this issue on the fork and we can get it merged and released.

EDIT: 🎉 I've archived the fork now that we've got some momentum in this repo and Jed is involved again. Sorry for the disturbance!

@colin-oos
Copy link

Are you guys changing the menuPortalTarget? I ran into this issue because I was using menuPortalTarget so the dropdown would display outside of my modal. I found out that the problem was because I was using document.body as my target but it was in fact my modal, not the body, that was scrolling. Using my modal as the target instead of document.body fixed the issue for me.

@MenachemICTBIT
Copy link

@colin-oos How do you target a specific element? I have a div that I want to use as my target, how would I reference it?

@qenibas
Copy link

qenibas commented Nov 27, 2020

Same issue here, got a lot of modals with height bigger than my screen (added overflow: scroll) - when do you think it'll be fixed?

@colin-oos
Copy link

@colin-oos How do you target a specific element? I have a div that I want to use as my target, how would I reference it?

You could use a React Ref or if you give your div an id then you can use javascript document.getElementById('my-divs-id') and pass that result into menuPortalTarget. If you use a react ref, I believe you'd need to pass this.myDivsRef.target into menuPortalTarget (I haven't actually tried with a react ref though)

@corwinstephen
Copy link

This seems like another one where the simplest fix is just to add menuPosition='fixed'. Upon further reading around that attribute, it looks like it's actually supposed to work properly (update its position on page scroll) and the fact that it doesn't is a longstanding bug. Weirdly, I noticed that if you scroll, and then hover over the open select menu, its position updates to the correct one.

I'm not sure why it's taken them so long to fix this, but it does seem like it will get fixed eventually. In the mean time, I think it should be fine to use fixed here the way it is.

@Methuselah96
Copy link
Collaborator

Methuselah96 commented Feb 1, 2022

I'm not sure of your particular situation, but using menuPosition='fixed' will not fix it for most people. If you go to the Cypress tests, scroll down in the portalled example, uncheck "Block Scroll", click "Fixed", and try scrolling either the page or the portal container it will not update the menu until you hover over it.

The attribute never worked properly because it has never recalculated the position on page scroll. I made substantial progress on this task a few months before I got sidetracked by releasing Redux DevTools 3.0. I hope to get back to it soon and my estimate is still months, but not years (starting from October 2021).

@man-trackunit
Copy link

May I suggest taking a look at Floating UI instead of popper when implementing this? Also, awesome work you do here. 💪 I'll see if I can convince my org to sponsor you.

@gajrajantino
Copy link

gajrajantino commented Mar 21, 2022

Why does this issue not occur on the official website? https://react-select.com/home

@gajrajgchouhan
Copy link

I was able to fix the issue using this commit !!

closeMenuOnScroll={(e) => {
    return e.target.contains(containerRef.current);
}}

I was looking for solution involving refs and without assigning unique IDs to the container. Hope this helps someone!

@Methuselah96
Copy link
Collaborator

Methuselah96 commented Mar 21, 2022

Why does this issue not occur on the official website? https://react-select.com/home

This issue only occurs when using portalling or fixed menu positioning.

@andrew-aladev
Copy link

Hello, I've reviewed react-select source code and found that it is easy to fix this issue: just rerender it on viewport update (scrolling, window resizing, etc). Rerender calls renderMenu function and everything will be fine. It will be good to add something like debounce for viewport events.

@Etheryte
Copy link

@andrew-aladev I doubt that's a realistic option, you'd have to consistently rerender at 60fps on top of everything else the browser is doing to avoid jitter, especially when considering many operating systems today use smooth scroll as default.

@andrew-aladev
Copy link

[email protected]

I've added simple patch for 3.1.0 version, you can easily adapt it for any other version.

I doubt that's a realistic option, you'd have to consistently rerender at 60fps on top of everything else the browser is doing to avoid jitter, especially when considering many operating systems today use smooth scroll as default.

Sure, absolute menu has move using jumps. I've added a patch for this solution. If user wants smooth movement than it has to avoid absolute mode.

Thank you.

@srinivasmerugu
Copy link

@Methuselah96 Could you please let us know if there is any plan of integrating popper for menu positioning as discussed here very long back for addressing scrolling issue with portal.

@Methuselah96
Copy link
Collaborator

The status remains the same as it was in my previous comments. I am hopeful it will be released by the end of the year.

@andrew-aladev
Copy link

andrew-aladev commented Jun 14, 2022

@Methuselah96 Could you please let us know if there is any plan of integrating popper for menu positioning as discussed here very long back for addressing scrolling issue with portal.

Unfortunately popper (like any other absolute solutions) won't help.

Absolute solutions uses left and top with pixel values for positioning popup. User have to bind on scroll events (+ any other event sources) and move left and top values for each visible popup. User is not able to move these values constantly (for each tick), because movement will consume 100% CPU time. User can move values fragmentarily, but in this case popup will move in fits and starts. So user have to add some transition for popup movements. We can see react-select developers don't like this solution.

So it looks like the only one possible solution is relative container and absolute popup without left and top pixel values. Popup placement (top-right, bottom-left, etc) can be received using left/top: +-0/100%. It is easy to implement, but requires full refactoring of interfaces, classes, etc. So please ask core developers for help with fixing this issue. Changes required for such refactoring is too heavy for any regular developer passing by.

@Sakib326
Copy link

Hope this helps someone

<div id="scrollContainer" style={{ overflowY: 'auto' }}>
  <Select
    menuPortalTarget={document.body} // Or document.getElementById('scrollContainer')
    styles={{
      menuPortal: base => ({ ...base, zIndex: 9999 }),
    }}
    closeMenuOnScroll={event => {
      return event.target.id === 'scrollContainer';
    }}
  />
</div>

thanks . it's helpful

@srinivasmerugu
Copy link

@Methuselah96 Thanks for the #5256 . Could you please let us know in which version of react-select it will accommodate.

@divinsmathew
Copy link

divinsmathew commented Sep 1, 2022

For me, simply adding the prop menuPortalTarget={document.body} fixed the issue.

@stephan-playbk
Copy link

as a hack, I've done the following:

  const [open, setOpen] = useState(false);
  const portalRef = useRef(document.getElementById('popover-root'));
  const selectRef = useRef<SelectInstance<Item, false>>(null);

  // ...

  // Bug in library - Dropdown doesn't scroll with page if using a portal
  // Remove this hack once the folling issue is closed:
  // https://github.com/JedWatson/react-select/issues/4088
  const hackToFixScrollingPosition = useCallback(() => {
    const controllerEl = selectRef.current?.controlRef;
    const menuEl = selectRef.current?.menuListRef;
    const menuControllingEl = menuEl?.parentElement?.parentElement;
    if (!controllerEl || !menuEl || !menuControllingEl) {
      return;
    }

    const controllerBounding = controllerEl.getBoundingClientRect();
    const menuBounding = menuEl.getBoundingClientRect() as DOMRect;
    const shouldPositionOnTop = window.innerHeight - controllerBounding.bottom < menuBounding.height;

    if (shouldPositionOnTop) {
      menuControllingEl.style.top = controllerBounding.top - menuBounding.height - 5 + 'px';
    } else {
      menuControllingEl.style.top = controllerBounding.top + controllerBounding.height + 5 + 'px';
    }
    menuControllingEl.style.left = controllerBounding.left + 'px';
  }, []);

  useEffect(
    function hackToFixScrollingPositionSubscriber() {
      let el: HTMLElement | null | undefined = selectRef.current?.controlRef;
      const listening: HTMLElement[] = [];
      do {
        if (el) { // ts pls
          el.addEventListener('scroll', hackToFixScrollingPosition);
          listening.push(el);
        }
      } while ((el = el?.parentElement));

      return () => {
        for (const el of listening) {
          el?.removeEventListener('scroll', hackToFixScrollingPosition);
        }
      };
    },
    [hackToFixScrollingPosition],
  );

  useEffect(
    function hackToFixScrollingPositionOnOpen() {
      setTimeout(hackToFixScrollingPosition, 100);
    },
    [hackToFixScrollingPosition, open],
  );

  // ...

  <Select
      ....
      menuPortalTarget={portalRef.current}
      ref={selectRef}
      menuShouldScrollIntoView={false}
      minMenuHeight={50}
      onMenuClose={() => setOpen(false)}
      onMenuOpen={() => setOpen(true)}
  />

@Methuselah96
Copy link
Collaborator

Methuselah96 commented Oct 12, 2022

🎉🎉🎉 This has been fixed in [email protected]. 🎉🎉🎉

Let me know if this addresses the issues experienced here. If there are more bugs to sort out related to menu positioning, please open new issues with CodeSandboxes using the latest version react-select. Thanks everyone for your patience!

@Dalton-Klein
Copy link

I have upgraded to 5.5.0 and haven't noticed any difference in this issue.

Unless I include these three options, the selects collide with each other when stacked vertically:

  • menuPortalTarget={document.body}

  • menuPosition={'fixed'}

  • menuShouldBlockScroll={true}

The issue with using these three options, is that it wipes all the styling I have set, and I cannot figure out a way to override the css styling when it is attached to the body.

@lukebennett88
Copy link
Collaborator

@Dalton-Klein, if you're able to make a CodeSandbox repro of the bug, I'd be happy to take a look for you.

@Etheryte
Copy link

Etheryte commented Nov 4, 2022

I can confirm that the 5.5.0 release works excellent and is buttery smooth. Thank you very much for everyone involved for your effort, especially @Methuselah96, this is splendid.

@IttzyTT
Copy link

IttzyTT commented Jul 13, 2023

Here's what I've been using. It's really hack-y and caused other problems, but it's the best I could do.

Because the position is fixed, if you need to scroll , the menu is pinned to the fixed position. The trick was to add an event listener that checks where the scroll occurs, and closes the menu if scrolling outside. The major problem this caused was, since it's used on a data table, the entire table rerenders every time you scroll, causing major stuttering. If your use case is more like a side menu, it might work.

I ended up using a different dropdown, in large part, because of this issue.

<Select isClearable value={value || ''} menuPortalTarget={document.body} menuPosition={'fixed'} // HACK: Specifying class name to force close dropdown. Issue with react-select libray (dropdown fixed position). // This CSS selector will almost certainly cause problems during deployment. closeMenuOnScroll={(e: any) => !e.target.classList.contains('css-4ljt47-MenuList')} options={suggestions} />

genius, works!

@ravivarma333
Copy link

ravivarma333 commented Jan 3, 2024

Screenshot 2024-01-03 at 12 42 49 PM

@Methuselah96 I see that when a div has the select tag from react-select and when you try to scroll the div the drop down of the select appears above of the divsion when scroll is extended.
The purple div is the original div and the drop down list should not appear beyond this, even after scrolling.

Dropdown going above other elements when scrolling to the end of the div.

Can you look into this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue/bug-confirmed Issues about a bug that has been confirmed by a maintainer issue/reviewed Issue has recently been reviewed (mid-2020) menu-bug Addresses menu positioning, scrolling, or general interactions
Projects
None yet
Development

Successfully merging a pull request may close this issue.