react-select: Dropdown remains fixed in place and doesn't scroll with parent container

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 - https://github.com/JedWatson/react-select/commit/691a01171969da89e20097f9d603651bb18a8510

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

Issues:

https://github.com/JedWatson/react-select/issues/4554 https://github.com/JedWatson/react-select/issues/4020 https://github.com/JedWatson/react-select/issues/4052 https://github.com/JedWatson/react-select/issues/3734 https://github.com/JedWatson/react-select/issues/4085 https://github.com/JedWatson/react-select/issues/3929 https://github.com/JedWatson/react-select/issues/3349 https://github.com/JedWatson/react-select/issues/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.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 47
  • Comments: 62 (1 by maintainers)

Most upvoted comments

Hi, has any progress been made on this issue?

🎉🎉🎉 This has been fixed in react-select@5.5.0. 🎉🎉🎉

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!

By way of an update, we have finished the Flow to TypeScript conversion and we’re taking a look at this issue as our next focus. Depending on how extensive the changes have to be to fix this, this might end up in either v5 or v6 (if it requires breaking changes). Thanks everyone for your patience.

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>

It has not been addressed yet. The plan is still to either release it in a minor release in v5 or in a major release in v6.

I would love to give an estimate of when this issue will be resolved, but unfortunately it is hard to give a realistic estimate since the work required to fix it is not trivial and the amount of time I have to work on open-source is not always consistent. On the scale of weeks, months, or years I think months is the most likely.

If you would like it to be accommodated more quickly, considering sponsoring me on GitHub Sponsors. If I get $50/month worth of sponsors from 5 or more new sponsors then my estimate would become weeks. Not because it’ll suddenly be worth my time, but because I want to encourage people to put their money where their mouth is. Alternatively, fork it and do it yourself. I can’t promise that we’d merge it back in, but you could use your fork until we get it fixed here.

I hope this doesn’t come across as uncaring, I just want to set realistic expectations. Having a library that’s consistently maintained is more valuable than having a library where the maintainers get burned out.

@srinivasmerugu Understood and agree that this is high priority. There are several open issues regarding menu alignment specifically when used with portaling. v4.2 should be getting released soon. Depending on how far out the TypeScript conversion goes, this would likely be the next big initiative to get resolved.

It was just brought up in a chat about how to handle this and we may look into using Popper so it is on our radar.

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.

This isn’t a fix for the issue, but I think it’s a nice workaround. I added menuShouldBlockScroll={true} prop and it blocks the body from scrolling when the select is open, that in my opinion is better user interaction.

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

Hope it’ll help someone. The problem is because MenuPortal by default is appending into document body. That’s why scroll has no effect on this portal. So the solution could be changing menuPortalTarget into container which wrapping select component and has relative position. Moreover by using menuPortal style its position should be changed into static (by default it’s set as absolute). Thanks to it menuPortal is relative to select component and scroll has effect on this menu.

Code example

const refSelectContainer = React.useRef(null);
<div ref={refSelectContainer} className={classes.select}>
   <SelectComponent
      ...
      menuPortalTarget={refSelectContainer.current}
      styles={{
        menuPortal: base => ({
           ...base,
           position: 'static',
           zIndex: 1000
        })
      }}

Styles

select: base => ({
   ...base,
   position: 'relative'
})

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

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).

To @Methuselah96 's point, there has been a lot of time put into keeping up with support both due to library issues and developer implementation. The primary focus was to release v5 which was a huge undertaking in rewriting the Flow types into TypeScript. The conception and efforts of this major release should be primarily accredited to @Methuselah96 for his work which started as a fork and then moved into the official release. I encourage anyone who wants to thank or support him for the move to TypeScript to sponsor him and I know that sponsoring those who dedicate their free time into maintaining this library would be appreciated.

To your question @srinivasmerugu, it’s part of the current focus. I think the challenging part of this is that there is no clear roadmap of what’s being worked on or what the plan is and I think we can do a better job communicating this. It’s hard to get collaboration from the community when there is no input on PR’s or any direction on what issues need to be addressed.

Version 5.0 was a major release to support TypeScript, remove the AutoSizeInput dependency, remove the absolute positioning from the ValueContainer children, etc… but moving to TypeScript forced us to have to put a lot of things on pause to avoid complicating an already complex merge.

Version 5.1 was released to resolve issues introduced from 5.0

Current priorities:

  • Documentation clean up and simplification
  • Fixing key values of MultiValues and transition of removing the last AnimatedMultiValue
  • Menu and MenuList bugs

Future considerations:

  • Make Emotion an optional dependency/unstyled Select
  • Create classNames api similar to styles api
  • Refactor components to hooks
  • Create standard and repo for customized community sets of components

There is talk already of V6 to determine which breaking changes we may want to make major changes to. I know a few of the maintainers/collaborators wouldn’t mind taking a look at how value represents the selectedOption(s) and not the values of those options, so this would be worth looking at as well. This would be a huge breaking change, but one that seems to be a popular one.

Regarding the Menu specifically, @Methuselah96 has a WIP looking to use Popper as the core of the positioning and sizing of the Menu, so it is underway and will likely be part of some upcoming minor release.

@Methuselah96, @ebonow Thanks for taking this issue as the next focus. Please consider it as on high priority.

Hey @bladey , @Methuselah96 , @ebonow Just to reiterate , the issue is still exist in latest version as well (4.1.0) I am using menuPortalTarget={document.body} and using it in a Modal/SlideIn.

Please find the video attached.

Could you please address this asap . It’s been pending from long time.

Thanks in advance!

https://user-images.githubusercontent.com/29884577/109163264-26d60e00-779f-11eb-8397-748b61be4ae1.mp4

react-select@3.1.0.zip

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.

This issue doesn’t only concern scrolling, actually. It’s also the same when you resize the window - the fixed menu, which renders in a portal (in my case that would be the document.body), doesn’t update its position when I resize the window. While it’s highly unlikely that someone resizes their window while the menu is opened, I can’t neglect the case when one has opened the menu on their smartphone and wanted to rotate it (which is basically changing the window size). The only way to reset the position in such cases is to close the menu and re-open it again manually.

Hey @ebonow and @Methuselah96, thanks for your speedy replies!

@ebonow that makes sense to address them all in a holistic way. This issue isn’t what I’d describe as urgent, but it is definitely important. I’m just glad to know that it’s still on the radar of the maintainers.

@Methuselah96 specifically we use it in a frameless Electron window, and what happens is it shifts the custom window border/titlebar we implement. The most exact match for our issue is https://github.com/JedWatson/react-select/issues/1843

Unfortunately I’m not sure how to recreate the issue. I spent hours tracking things like scrollHeight and offsetTop for the root element of React-Select, and traversing upwards through every node. I couldn’t find any differences in any properties I could think to check between before opening the menu (non-broken layout) and after (broken layout.)

The only, only, only other thing that remedied the issue was using html { contain: content; } which prevents the contents of html from affecting the layout outside of it, but that workaround has a number of issues too.

At first I didn’t realize menuPortalTarget didn’t have to be a React portal, so I tried using our own portal created with React-DOM, but the outcome was the same.

I then tried document.body when I saw that suggested many times, which eventually led me to passing in the DOM node for the scrollable container our React-Select resides within, but even that made no difference in behavior. I confirmed the menu renders at the expected place in the DOM, so the inability of any of these options to affect the issue really confuses me.

I also tried menuShouldScrollIntoView and menuPlacement="auto" while grasping at straws. I then tried 3.2 and 4.0 in the past half hour, but the behavior (without position="fixed") is the same. I didn’t expect it to be fixed, but just to confirm it persists in the newest versions.

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.

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.

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!

Still an issue. Cannot figure a way to work around it.

@ArekMiszcz Similar suggestions have been brought up in the older tickets linked above, that approach only works in layouts where overflow breakout isn’t necessary and doesn’t address the general problem. In fact in most of the layouts where this does work you wouldn’t need portaling to begin with. Glad if it fixes the issue for you though.

@Methuselah96 Regarding funding, I reached out within SUSE to inquire about possible options and in brief we only fund foundations (such as the OpenStack Foundation, Cloud Native Computing Foundation etc). If this project was part of an open source foundation then us sponsoring that foundation in turn might be possible. Something for your consideration regarding the longevity of this project. In the interim, I will try to familiarize myself with the project and see if I can help with the Popper integration or an alternative solution.

I used a workaround to disable the outter scrollable when the dropdown is open. In my case, I just set the overflow property from scroll to hidden. Hope this works for someone’s case.

Greetings @Slapbox ,

Part of the version 4 release included a refactor of the scrollCaptor and menuPositioning into a single scrollManager. We have also added a menu label to the existing PR’s which address menu behavior so that we can address them holistically instead of ad hoc.

I’m currently focused on addressing some of the underlying accessibility gaps with the aria live implementation, but hope to focus on the menu issues right after.

This is bad. No way i could out a way to fix this. Can someone help please.

@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)

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

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?

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

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

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.

@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.

@Slapbox What’s your use case? Are you using it in a modal? What are you using for menuPortalTarget? If you could create a CodeSandbox detailing your specific problem that would be the most helpful. ~Many of the issues described above have to do with setting the menuPortalTarget to document.body when the body is not the element that’s actually scrollable.~ (I was misunderstanding the problem when I said this.)

@bladey How is it going? Could you please provide an update on this. Issue still present in latest versions.

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 https://github.com/JedWatson/react-select/issues/3929#issuecomment-604866966.

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: https://github.com/JedWatson/react-select/issues/810#issuecomment-398563946)