I have my own search input. When I enter a value into it, I have items matching the search terms displayed. I need to show these elements only when the input is in focus, and hide them when blurred. But here's the problem: when I click onClick on one of the items, I need to perform some actions but I don't want onBlur to be triggered. But when I click on an element, onBlur is triggered, which causes the elements to be hidden and the onClick event for the element is not triggered.
I tried using event.stopPropagation() and event.nativeEvent.stopImmediatePropagation(), but that didn't help. For some reason onBlur always triggers first even when the components order is changed.
<Container className='search-widget'>
<div className={field-wrapper}>
<SearchField
onFocus={() => {...}}
onBlur={() => {
console.log('onBlur')
}}
/>
<Button onClick={...}>
<img src='/images/Search/search.svg' alt='search' />
</Button>
</div>
<SearchList
itemOnClick={data => {
console.log('onClick')
}}
/>
</Container>
When onClick to element. onBlur is triggered and the menu is hidden
You need to use relatedTarget
One way could be to use a ref like below. NOTE: this answer assumes that SearchList
only contains clickable DOM items. If it renders things that are more than just clickable items, then it won't work if you click on something that is inside SearchList
that isn't an item.
Ultimately, relatedTarget
is what you need. There's a myriad of ways that might work for you in how you choose to use it.
const searchListWrapper = useRef()
return (
<Container className='search-widget'>
<div className={field-wrapper}>
<SearchField
onFocus={() => {...}}
onBlur={(e) => {
const didClickItem = searchListWrapper.current.contains(e.relatedTarget);
if(!didClickItem) {
// user clicked something other than an item, do stuff
}
}}
/>
<Button onClick={...}>
<img src='/images/Search/search.svg' alt='search' />
</Button>
</div>
<div ref={searchListWrapper}>
<SearchList
itemOnClick={data => {
console.log('onClick')
}}
/>
</div>
</Container>
);