Closed jbyomuhangi closed 3 years ago
Seems like there are some key press events that are being blocked from reaching the custom Control component, I changed MyCustomControl as follows to log every time the onChange
event fires, and it doesn't fire when some keys are hit (space-bar, backspace, delete for example), but it does fire with others (the letters on the keyboard for example)
const MyCustomControl = (props) => {
return (
<components.Control {...props}>
<input type="text" onChange={() => console.log("change is happening")} />
</components.Control>
);
};
This could be because the input element is not controlled. Trying setting the value on each onChange event.
Also if you want to handle backspace, enter, delete, try onKeyDown or onKeyUp to handle those events. onChange might not get triggered on those keys.
But that's the thing, onChange
should be getting triggered, It gets triggered on a normal input element when you try do all that. To my understanding the only events that should be stopped from propagation are the ArrowUp
, ArrowDown
and Enter
key presses, and this should only happen when the select menu is open to allow for keyboard navigation and option selection right? I think these other keys are being stopped as well somewhere in react-select, causing this problem.
Greetings @jbyomuhangi ,
I believe part of the issue here might be your custom Control component. You seem to be replacing the component with an input which is not expected behavior.
Control The second highest level wrapper around the components. It is responsible for the positioning of the ValueContainer and IndicatorsContainer. It is followed by the Menu.
As for why these keys do not work as expected, the Select Container has keyDown bindings to control special behavior which is then used to trigger different events within the control. You can see the complete list of keys that are bound here
That said, is there some kind of behavior you are trying to accomplish by passing in an input as you are for the Control component?
HI @ebonow ,
Yeah, so I have an input component that has some complex logic behind it, it's a rich text editor of sorts. I want this editor to be able to trigger the select menu given specific conditions, so I thought I would be able to replace the control to open the menu and write my own logic to handle opening and closing it. Basically I wanted to switch out the area where the user would type in a searchable select for my own component, but doing so doesn't seem to be possible.
Have you tried replacing the Input component instead of the Control? Also, you should be able to control the menuIsOpen
prop in state without having to write a custom Control component.
If you provide a codesandbox, I might be able to offer whatever insight I can into the functionality you are trying to achieve, but I have come across some difficulty before in the past trying to work with this component as it frustratingly does not provide access to the same common props as other custom components.
Yeah, tried making it the Input instead of the Control but same thing happens. Here's a link to the sandbox I just made that simulates a crude example of what I'm trying to do: sandbox
Triggering the opening and selection works no problem, but the input itself breaks down and is unable to receive event like "backspace" and "delete"
If you do use the Input component, you could pass the props along and they will be applied directly to the Input. One example would be passing any kind of attributes you would want to the input, for example, maxLength...
const Input = (props) => {
const { maxLength } = props.selectProps;
const inputProps = { ...props, maxLength };
return (
<components.Input {...inputProps} />
);
};
And here is a sandbox for it: https://codesandbox.io/s/react-select-custom-input-yir19
Conceivably, you should be able to pass other attributes or events but I am not sure if you would be able to recreate the custom logic you are applying to your existing inputs without too much effort.
Hope this helps some.
If you have any other questions, feel free to follow up and we can always reopen this if necessary.
I think I have a better way to illustrate the problem and what I am trying to do. Here is the updated code sandbox link.
In this example, I want to open the menu by clicking something, could be anything, and still have the normal behavior of the selector. Given the selector is not searchable the docs say this:
If the select is not searchable, a dummy input is rendered instead
It appears that this dummy input that is rendered when a selector is not searchable has control of the key presses and if it it not rendered, key presses are not handled correctly. This can be seen in the sandbox link, try doing the following to see the behavior:
Enter
to select an option. You will see that when you comment out line 20, you lose the keyboard controls, so my question is, why does this happen, and what component is responsible for the focus management?
How can I achieve what I'm trying to do with react-select?
@jbyomuhangi Fortunately, this is not an issue. Full explanation and working demo below
You will see that when you comment out line 20, you lose the keyboard controls, so my question is, why does this happen
First, an explanation of the impact of line 20
props.children[0]
of the Control
is the ValueContainer
which contains the DummyInput
DummyInput
is the element responsible for receiving focus when the Select is clicked onBut, what about the button?
console.log(document.activeElement)
reveals that the focus is on the body, so the keyDown events are no longer captured by the Select.what component is responsible for the focus management
- Focus is mostly managed by the Input. There are internal methods which set
isFocused
state onFocus and onBlur- The keyDown listeners are set on the Select container which control the menu which in turn sets the "focusedOption" https://github.com/JedWatson/react-select/blob/998c979b4ed51ee39b87c9b2f0f03da440017dcf/packages/react-select/src/Select.js#L1845
How can I achieve what I'm trying to do with react-select?
- You simply need to maintain focus within the SelectContainer so that the keyDown listener will be able to control the Menu.
const Control = (props) => {
const onClick = e => e.target.focus();
return (
<components.Control {...props}>
<button onClick={onClick}> hello </button>
</components.Control>
);
};
I hope this answers all of your questions. It wasn't entirely intuitive for me either, especially realizing that the button wasn't maintaining focus. I will close this issue as everything does appear to be functional, but happy to work through any other questions you have. As before, I can reopen this if necessary.
Wow, thanks so much @ebonow! This works! Really appreciate the help and speedy replies
I am facing issue 's where I've select component inside which we show input field in the option, when we try clicking the spacebar , arrow keys the it doesn't works, I guess this behaviour is being handled by the Select component. but it should be only for the input field used by Select and not to other components
I'm using react-select v3.1 and I'm experiencing some very odd behavior, not sure if I'm doing something wrong or if there is a bug.
Scenario : I am making a custom select and I want to create a custom Control that the user can type in to perform searches.
Expected behavior: User can type normally in the custom Control to search for an item to select
Current behavior: Custom Control is made but the typing experience is not working correctly. Some key presses aren't being triggered in the custom control such as backspace, space-bar and delete. Here is some code that illustrates what I am currently doing and the result (this is just for illustration):