3

Full reproduction: codesandbox link .

I am trying to create a custom search/select component with react. My problem lies in execution order of events.

When a user focuses in on the text input field, a list with options should be shown. Then when the user clicks on one of the items in the dropdown, the element name should be filled in the text input field and then the list should be hidden.

I achive this by creating a inputFocused boolean state, and rendering list only when inputFocused is true. I attach twop event handlers on the text input itself:

  • onFocus={() => setInputFocused(true)}
    
  • onBlur={() => setInputFocused(false)}
    

But when a user clicks on one of the items, input is not getting filled.

<input
   value={searchTerm}
   onChange={(e) => {
     setSearchTerm(e.target.value);
   }}
   onBlur={() => setInputFocused(false)}
   onFocus={() => setInputFocused(true)}
/>
{inputFocused && (
    <ul>
        <li onClick={() => setSearchTerm(element.name)}>{element.name}</li>
    </ul>
}

Check codesanbox link for better understanding.

I think i understand the problem. onBlur() event triggers before the onClick() event. If i wrap the onBlur callback function inside a setTimout, it will work as expected:

onBlur={() =>
    setTimeout(() => {
        setInputFocused(false);
    }, 100) 
}

I would like to avoid defining a setTimeout.

Is there solution to make sure that onClick() on <li> executes before onBlur() on <input /> ?

timtheone
  • 33
  • 4
  • You can experiment with this https://stackoverflow.com/questions/32553158/detect-click-outside-react-component but I guess it won't work with keyboard so well – Konrad Jan 05 '23 at 21:00
  • I have tried that as well. Same problem. https://codesandbox.io/s/evet-order-execution-forked-bjkt1y?file=/src/App.js . – timtheone Jan 05 '23 at 21:30

1 Answers1

1

You can change onClick to onMouseDown on the list items, and the ordering will be handled properly by the browser.

The events get fired in the order of mousedown -> mouseup -> click (see https://javascript.info/mouse-events-basics#events-order)

corypis
  • 71
  • 6
  • Thank you, that did help. Although, this introcuded problems with `mouseDown()` capturing not only left mouse clicks, but also a middle mouse click, etc, but anyway that did answer my question! – timtheone Jan 06 '23 at 14:17
  • ah ok, you can check `event.button` if you want to ignore or only respond to certain click types https://developer.mozilla.org/en-US/docs/Web/API/Element/mousedown_event – corypis Jan 06 '23 at 16:13