Last active
August 1, 2023 21:00
-
-
Save pstoica/4323d3e6e37e8a23dd59 to your computer and use it in GitHub Desktop.
onBlur for entire react element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function OnBlurComponent({ onBlur }) { | |
const handleBlur = (e) => { | |
const currentTarget = e.currentTarget; | |
// Check the newly focused element in the next tick of the event loop | |
setTimeout(() => { | |
// Check if the new activeElement is a child of the original container | |
if (!currentTarget.contains(document.activeElement)) { | |
// You can invoke a callback or add custom logic here | |
onBlur(); | |
} | |
}, 0); | |
}; | |
return ( | |
<div tabIndex="1" onBlur={handleBlur}> | |
Hello <input type="text" value="world" /> | |
</div> | |
); | |
} |
OMG, you are a genius! Thank you so much for sharing this!
@pstoica
Thanks for this! Just a heads up, I think you forgot to change the callback onBlur={onBlur}
to onBlur={handleBlur}
in the newest revision:
return (
<div tabIndex="1" onBlur={handleBlur}>
Hello <input type="text" value="world" />
</div>
);
@pstoica
Thanks for this! Just a heads up, I think you forgot to change the callbackonBlur={onBlur}
toonBlur={handleBlur}
in the newest revision:return ( <div tabIndex="1" onBlur={handleBlur}> Hello <input type="text" value="world" /> </div> );
glad it helped. thanks for catching that, updated!
You're my hero!
That helps a lot!
You can also use event.relatedTarget
to get the next active element on blur if you don't care about IE 11.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Super useful! Just spent a day going through tons of pages on blur and focus to figure out an annoying bug that was preventing my onclick handlers in a child component from firing. I was using it for a dropdown component based on the details/summary html element to remove the open attribute on blur so only one dropdown menu would show at a time, but the blur event goes first, adding the open attribute, and triggering a rerender before the child component's onclicks could fire.
This also helps me out because one of the dropdowns I needed to keep it open when they clicked within it because there were some input interactions in the dropdown menu. Also had to add tabindex=0 to my dropdown element so the focus info would pass correctly.
The other thing was it wouldn't work for me until I set the timeout to a longer time, around 50-100ms. Not sure exactly why, but I'm guessing it's because React doesn't trigger renders immediately after changes, instead batching the changes then updating all at once. I think that extra time makes it wait long enough for that to happen before triggering my blur handler.
Here's what my the details element in my render function looked like:
Anyway, just sharing my frustrations in case anyone else finds it helpful