Catching the blur event on an element and its children
Recently I implemented a fly out menu in React, and stumbled on the following problem - I had to catch a blur event on the menu, but it had multiple focusable children. When user is tabbing between these menu items, blur event is triggered every time on the parent, followed by the focus event on the next item. As I wanted to close the menu on blur, this would close it before user was able to get to the next menu item.
Solution is fairly simple and it is not React exclusive - it can be used with any other framework or vanilla JavaScript. The flow goes something like this:
- Listen to a blur event on the parent element (in my case it was the menu). This will catch blur event on all of its children too.
- In the handler, give browser time to focus the next element (by using
requestAnimationFrame
). - Check if the newly focused element is in our parent element.
- If it is, do nothing, as focus hasn’t exited the parent yet.
- If it is not, we left the parent element completely and it is safe to do our blur logic (in my case, it was closing the menu).
Code looks like this:
;
React component
I pulled out the logic and created a small React component:
;
and usage is pretty straight forward:
Demo
To see it live check the demo on Codepen:
I really like this technique, and I found it useful in multiple places like tooltips and dropdowns, where it can replace “outside click” listeners.