Closed steinso closed 4 years ago
Facing the same issue. I think an expected behaviour would be to maintain the scroll position of the menu on selecting an option and just pull up the remaining options in the list.
+1 If the PR of @steinso is OK, is it possible to merge ?
+1
+1
+1
Maybe it's been fixed in the meantime, but for me in multi
mode it's actually scrolling to and highlighting the option immediately following to the last selected option (which is removed from options in multi mode), which I assume is the desirable behavior.
But, I wish there was at least a setting to always leave the scroll position at the top when opening the menu, whether multi-select or single. I have no interest in retaining the scroll position of the last selected item for my use case, and the best way I have found to eliminate this is to edit the source code, in componentDidUpdate, I just commented out the first if
statement block...
key: 'componentDidUpdate',
value: function componentDidUpdate(prevProps, prevState) {
// focus to the selected option
if (this.menu && this.focused && this.state.isOpen && !this.hasScrolledToOption) {
var focusedOptionNode = _reactDom2.default.findDOMNode(this.focused);
var menuNode = _reactDom2.default.findDOMNode(this.menu);
menuNode.scrollTop = focusedOptionNode.offsetTop;
this.hasScrolledToOption = true;
} else if (!this.state.isOpen) {
this.hasScrolledToOption = false;
}
If there was an option to disable scrolling (and highlighting), the last selected option (which ends up being the next adjacent option in multi mode), it would be great.
Hi everyone!
I'm still facing the issue with scroll. I'm using V2 of the component and as I see everything has changed. I cannot find the above code anymore. Do somebody deal with it in 2019? Maybe I missed some component option. Or there is another part of code caused the issue.
This is critical for me as I'd like to keep multi-select opened while a user selects options. The idea is to close the dropdown when a user clicks on submit button inside it. But the dropdown scrolls up every time a user selects an option and this makes the idea totally unusable.
Is it possible to fix the issue on my side?
+1
@vitaliikobrin did you found a solution to this? I am also facing the same issue
Any news on this issue? Is there a some kind of workaround?
Experiencing the same issue. In my case I use the multi option and a custom menu selection popup. On the first click anywhere in the popup container it will scroll to top in case the input is not visible in the page.
+1
@bladey why not confirmed? this is a huge bug
Hi @aliazizi, thanks for your feedback.
Can you please confirm this issue is still affecting v3
of react-select
?
In an effort to sustain the react-select
project going forward, we're cleaning up and closing old issues using v1
and v2
of react-select
.
In the best interest of supporting the broader community we have to direct our efforts towards the current major version v3
and beyond.
Hi @bladey , I'm not the author.. but I can confirm this issue in 3.1.0.
Thanks @alikrodrigues, I appreciate the feedback.
@alikrodrigues I just tweaked the sandbox example and I'm unable to reproduce the issue, could you let me know what I'm missing from my config (it also works when searching and selecting).
Hi @bladey thanks for answered, When I use a wrapMenuList to show the selected the focus will redirect to MenuList.. When I removed and show just the badges the work it's ok..
Here is my Select Component
and here is my MenuList
[edit]:
My versions
@bladey I reproduce the problem
You can see it here
https://codesandbox.io/s/react-codesandboxer-example-5xmq0?file=/index.js
The problem happen when override MenuList component with hideSelectedOptions
and closeMenuOnSelect
set to false
Can you confirm this bug now?
Update:
The poblem also exist when overwirte Menu
component
Running into this issue also, I have a custom Menu Item component and closeMenuOnSelect set to false. Have you found a workaround to this issue or is this just a bug that can't be solved
@aliazizi Common mistake with Reacts render
method: You are defining your MenuList
component inside the render
method. As this method is called on every change to the components state, the MenuList
component is also redefined every time, which causes the HTML element to be replaced and the scroll-to-top to happen.
Solution: Move your component outside of the render
method.
const MenuList = () => { /* ... */ };
/* ...*/
render() {
return <Select components={{ MenuList }} />;
}
Thanks for the answer @Rall3n!
I can confirm this works, I modified the Codesandbox here - https://codesandbox.io/s/react-codesandboxer-example-4mj9p?file=/index.js
The problem no longer exists for me @aliazizi and @calvinherd9, let me know.
@Rall3n! thanks, it's working
@bladey thank you it's working now
Thanks guys, It's working for me too.
@Rall3n I spent 2 days off looking for a solution and trying to fix this bug. how everything turned out to be trite. thanks !
A note for anyone else who was struggling with this: React Select seems to use object identity matching under the hood to determine which values are selected. That means if you programmatically generate your {label, value}
object every render, React Select will have trouble keeping track of it.
For example: the following code will cause React Select to jump to the top after every selection, because different objects are passed to React Select every render (even though they have the same values):
import React { useEffect, useState, useMemo } from "react";
import Select from "react-select";
import axios from "axios";
function BlogPostSelect() {
const [posts, setPosts] = useState(null);
useEffect(function getPosts() {
axios.get("/api/posts/)
.then(({data}) => {
setPosts(data);
})
}, []);
// New objects are created every render.
function makeSelectOptions() {
return posts.map(post => ({ label: post.title, value: post.id }))
}
if (!posts) return;
return (
<Select
multi={true}
closeMenuOnSelected={false}
hideSelectedOptions={false}
options={makeSelectOptions()}
)
}
On the other hand, if we computed the list once with useMemo
, the objects would keep their identities, and React Select would maintain its position and not jump to the top after you select an item.
import React { useEffect, useState } from "react";
import Select from "react-select";
import axios from "axios";
function BlogPostSelect() {
const [posts, setPosts] = useState(null);
useEffect(function getPosts() {
axios.get("/api/posts/)
.then(({data}) => {
setPosts(data);
})
}, []);
// This is now memoized, so objects maintain their identity.
const selectOptions = useMemo(() => {
return posts.map(post => ({ label: post.title, value: post.id }))
}, [posts])
if (!posts) return;
return (
<Select
multi={true}
closeMenuOnSelected={false}
hideSelectedOptions={false}
options={selectOptions}
)
}
Hopefully this helps someone in the future. I didn't actually run the code above so there may be a couple of typos, but this general concept got this working for me.
In my case, I want to send some callback functions [onChange] and properties in the menu list component but when I pass them somehow scroll is not working [when the item is selected it scrolls to the top]
I modified the Codesandbox here https://codesandbox.io/s/react-codesandboxer-example-forked-s0320q?file=/index.js
can anyone please help me with this? thanks
@ektak26
In your example, it looks like you are still returning a new MenuList on every render with how you have MenuList: (props) => ....
. If you define it without a function that gets called on every render, then it works. Take a look at this fork of your sandbox: https://codesandbox.io/s/react-codesandboxer-example-forked-t1fytw?file=/index.js
The main thing is that I defined const customComponents = { MenuList: MenuListCustom };
outside of the component (or you can wrap it in a useMemo if you want) and then for your Select
component I have the prop:
<Select
... other props
components={customComponents}
/>
Please use useCallback with MenuList. That will work. const MenuList = useCallback((props: any) => { return (
);
}, []);
@vijay1479 you saved my life!
@ektak26
In your example, it looks like you are still returning a new MenuList on every render with how you have
MenuList: (props) => ....
. If you define it without a function that gets called on every render, then it works. Take a look at this fork of your sandbox: https://codesandbox.io/s/react-codesandboxer-example-forked-t1fytw?file=/index.jsThe main thing is that I defined
const customComponents = { MenuList: MenuListCustom };
outside of the component (or you can wrap it in a useMemo if you want) and then for yourSelect
component I have the prop:<Select ... other props components={customComponents} />
what if I need to add a button to change the state at the top of the list? still looking for a solution, I have something like that, and it keeps scrolling to the top as soon as I select an option
const MenuList = (props: any) => {
return (
<components.MenuList {...props}>
{selectedAccounts.length > 0 ? (
<button className="btn btn-link" onClick={() => setSelectedAccounts([])}>
deselect all accounts
</button>
) : (
<button className="btn btn-link" onClick={() => setSelectedAccounts(accounts)}>
select all accounts
</button>
)}
{props.children}
</components.MenuList>
)
}
i am using a custom menuList with customFilter placed above the ul and the menu scrolls to top as soon as I select any option in isMulti mode...is there a solution to this problem?
Problem: After selecting an option in a multi-select enabled component, the option menu automatically scrolls to the top.
I have debugged this a bit, and it looks like the reason is that on render it wants to focus the selected option, however in multi-select mode, that option is removed from the option menu. This makes it default to the first element in the menu.
5th line in render function, and this.getFocusableOption.
One way to go about this could be to find the adjacent option in the props.options list, and then find the same option in the _visibleOptions list.