Like mouse enter/leave, these are almost always what you want, not the onFocus
and onBlur
events we currently expose. I run into this semi-frequently when actually doing product work. We should add them.
FWIW, I agree with you. People know about focusin/focusout, and so we should just make them work, despite the fact that they would map to the exact same event handler we use for focus/blur.
However, last time this was discussed, we opted to not do this (https://github.com/facebook/react/pull/6226) and decided to warn instead (https://github.com/facebook/react/pull/6296/files).
I'd be fine with reversing this decision if you can get the momentum within the team.
It looks like it was decided against because of an incorrect claim that they're indistinguishable from onFocus/onBlur. onFocusIn/onFocusOut is different in that when moving focus between two children of an element, neither event fires on the container.
Doing it properly means adapting the logic in EnterLeaveEventPlugin and isn't as simple as adding it to SimpleEventPlugin.
Ah, that makes sense. Thanks for explaining!
Adding “good first bug” here. Note @spicyj’s comments: they need to behave like onMouseEnter
and onMouseLeave
. You’ll want to look at EnterLeaveEventPlugin
.
I'd like to work on it if nobody minds. Enough with the tests, time to add real source code!
Hey @gaearon @spicyj apparently there is a confusion here, let me explain.
mouseover
and mouseout
bubble up. mouseenter
and mouseleave
don't bubble up. Corresponding React event handlers work the same as native events - awesome.
Native focus
and native blur
events don't bubble. Corresponding React event handlers onFocus
and onBlur
do bubble - dun dun dun.
Native focusin
and native focusout
events do bubble. React events for these should be implemented and bubble too.
Here is a jsfiddle I made to display this. Checked in Chrome only, as since MDN documentation states that this is intended behavior then I believe it should be the same in other browsers.
If I am right about this (please correct me if I am wrong), then the following should be done:
onFocusIn
/onFocusOut
should be removed (obviously).onFocus
should be renamed to onFocusIn
; onBlur
- to onFocusOut
as they currently work the same as native onFocusIn
and onFocusOut
work - they bubble.onFocus
and onBlur
event listeners should be implemented in React - which will not bubble.Hmm, that sounds plausible. Thanks for the correction. Kinda annoying that we'll end up renaming these for people but maybe it's for the best.
Hey, unfortunately, I cannot invest time in this right now and I must pause. I have added onFocusIn/Out by mimicing onFocus/onBlur but I am having issues with changing onFocus/onBlur so they don't bubble.
I don't want to slow down the awesomeness of React so if anyone wants to invest into this issue - please do. If nobody does - I will get back to it when I have more time. Good luck!
but I am having issues with changing onFocus/onBlur so they don't bubble.
Do we want them to not bubble? We had previously said that all events bubble. I'm fine with whatever, so I'll leave that decision to @spicyj since he has the most situational awareness here.
Since this is tagged as a good first bug I thought I'd take a stab at this. Let me know if you're still working on it @cbrwizard !
I did a little more investigating and it looks like focusin and focusout events are not supported by Firefox. Is this still something you want to implement if all browsers don't support it? See here: https://developer.mozilla.org/en-US/docs/Web/Events/focusin and here: https://bugzilla.mozilla.org/show_bug.cgi?id=687787
@mrscobbler It should be possible to polyfill the event on any browsers that don't natively support it. We do this with several events that are not supported on particular browsers.
Ok! Good to know.
Any status on this?
So I've spent a few hours figuring out the events code (I've never looked at it before) and I've made some progress. Possibly @cbrwizard could walk me through some of what he's done? I might get a better understanding of what needs to happen. @trigun539 is it something you want to tackle or do you just need/want it finished?
@mrscobbler @spicyj Was it ever decided that this is something that should still be implemented? Seems like the discussion of whether or not this should be added based on the fact that all events currently bubble kind of ended without a consensus. I'd be willing to help out with this if we decide to go further with it.
I am working on an app that needs to be 508 compliant, and have a flyout menu where the last inner submenu li element should fire a focusOut event (for the parent li) when you go past it. However, it doesn't fire it. I have added the onBlur event and it doesn't work as expected. I can take a look at this.
Navigation is all done through keyboard.
@trigun539 Can you post a code example by any chance? I just created a basic example with a ul and two li's that each have an inner anchor and after adding onFocus and onBlur events to the li's, the events fire correctly and bubble up from the inner anchors.
@anthonybarsotti the set up is more around the following:
`
If I tab when I am on the "last li" I should go to "Another test" li, but it should fire an onBlur event on the "parent item" li. I'll post a sample after I get it set up.
@mrscobbler Can we please work on it together? I wish to contribute.
@rishirajsurti Yes! I'll send you an email. @anthonybarsotti @spicyj has it been decided whether or not we should move forward with this?
if anyone here needs some insight on the event code, feel free to ping me. I've some experience with it, (PR's in the past) and would also like to see this.
ALSO the current mouseEnter/Leave logic is crazy I really don't think we should emulate it again for new features if possible. I've already spoken to @jimfb a bit about that though. For insight as well there is this outstanding PR which simplifies the mouse logic, it might be helpful stratgey for this case as well: https://github.com/facebook/react/pull/5762
Wait, are we trying to add focusIn/Out as analogs to mouseEnter/Leave? Personally I rarely want the behavior of native focus/blur events. I do however almost always want for focusEnter/Leave like events...
@jquense Yeah I think that's the idea, the bigger question is that since the current onFocus and onBlur events bubble should those events just be renamed and have new events implemented for onFocus and onBlur that don't bubble?
Thats where my confusion comes from. mouseEnter and mouseLeave _do not_ bubble; that's much of the point of them, but they also _do not_ behave like native focus/blur, which only fire when a the element that attached the handle gains focus _not_ when it or any of its children gain focus.
so I'm not sure why we'd need to invert the behavior, unless the goal is to not actually add something like focusEnter/Leave
I know this might be unrelated / wrong thread for this, but when I use onFocus
or onBlur
events on an input
element in my React app, if i set the value to an empty string in the event handler, I get TypeError·TypeError: property "value" is non-configurable and can't be delete
Looking at the stack trace, it's because it is trying to delete the value and detach the onPropertyChange
handler: attachEvent("onpropertychange",d):A.addEventListener("propertychange",d,!1)}function f(){A&&(delete A.value,A.detachEvent?A.detachEvent("onpropertychange",d):A.removeEventListener("propertychange",d,!
any idea what might be causing this?
@iam-peekay Please file a separate issue, ideally with a repro case that exhibits the problem.
It seems like this issue has stalled, so let me weigh in with a summary. There are two separate features that a focus/blur event handler can provide:
If I understand correctly, here's how I think the current handlers are defined:
| Implementation | focus handler | blur handler | bubbles | encapsulated |
| :--- |:--- | :--- | :---: | :---: |
| React | onFocus
| onBlur
| Yes | No |
| Native | onFocus
| onBlur
| No | Yes[1] |
| Native | onFocusIn
| onFocusOut
| Yes | No[1] |
There are two changes being discussed in this issue:
Bringing the react event spec in-line with the DOM. It seems to me like simply adding a check for event.target === event.currentTarget
would be enough to turn a bubbling event into a non-bubbling one, but I'm not sure whether there needs to be more work on error handling or something, and whether that approach would work with React Native. It seems like the impetus behind this change is about consistency with the DOM.
Creating a variant of the focus event that is encapsulated. This can be done in the DOM world with event.currentTarget.contains(event.relatedTarget)
, but that requires querying the DOM. Not sure if this is possible with RN. This change is about adding a new behavior to React.
[1] [The spec](https://www.w3.org/TR/DOM-Level-3-Events/#events-focus-types) does not explicitly describe this behavior, but it is implied by the requirements. It can also be confirmed in this fiddle
I'll jump back here since I dealt with this once again :P Thanks @felipeochoa for the table.
In my experience I almost never want either of the native focus events (tho react should offer them), instead I want focus events that do not bubble and are encapsulated (as termed above)
I'd suspect tho at this point that may be unlikely as it would require a new polyfill
O i'd add that you can't actually adapt the mouseEnterLeave logic for this, since IE11 doesn't have a relatedElement
set on the focus/blur events :(
Hi folks 🙂 any progress on this?
Similar to what @jquense mentioned, in IE10/11, blurEvent.relatedTarget
is null
. (Microsoft is tracking - and not fixing this so far! - here and here.) focusOutEvent.relatedTarget
is populated as expected.
But React strips out onFocusOut
props, thereby leaving no way to access relatedTarget
in IE10/11.
@awreccan For the time being, you might be able to use the following workaround for relatedTarget
:
setTimeout(() => {
const relatedTarget = document.activeElement;
// ...
}, 0);
As I see, this issue is still open, can anyone update us on the progress, please?
I need onFocusOut
so I can run things if the user focuses out of the whole element, opposed to onBlur
which will fire if any child gets the focus.
Meanwhile, is there any workarounds?
Here is an example of how I would use onFocusIn
to toggle a user experience:
https://codepen.io/jonneal/pen/JpdmBm/
^ In this example, I’ve used the focusin
and focusout
events to trigger a classname change on a parent element. The parent contains two visible controls. We can focus on either control to trigger focusin
and reveal additional siblings. With these additional elements revealed, we can now focus on the original controls or these newly revealed elements without changing the "focused" state of the parent element. We can also focus off all of these elements to trigger focusout
and hide the additional elements; making things appear as they did before.
Using defaultValue attribute worked for me in case of onblur.
The encapsulation behaviour is really strange and unpredictable. Is it expected to be solved?
I ran into this issue when working with window.getSelection(); there are workarounds, such as onmouseout, onmouseup, and document.onselectstart. But it would be nice to have an input onfocusout to grab the selection at that event time.
can anyone update us on the progress
If you don't see any updates, it means there have not been any updates.
I agree it would be great to solve it. If you can write up a proposal for how it should work, and what the migration steps would be, that would help move the progress forward. :-)
As of React 16.5.2
focus event bubbles
field is always set to false
meanwhile it is still bubbling.
I think this is an issue and _(a separate report must be probably filled, but anyway)_ must be addressed either
bubbles
into true
in order to eliminate confusion.Here is an example of bubbling event: https://codesandbox.io/s/6lron03zyw
...
<span onFocus={this.onFocus}>
<input type="text" value={placeholder} />
</span>
I need onFocusOut so I can run things if the user focuses out of the whole element, opposed to onBlur which will fire if any child gets the focus.
@M-Dahab I don't think you need onFocusOut
for this. You can use an onBlur
handler like this:
handleBlur = (e) => {
if (!e.currentTarget.contains(e.relatedTarget)) {
// focus is leaving the container so do something interesting here
}
@craigkovatch this is precisely why we need onFocusOut
. Some browsers do not set event.relatedTarget
for the blur
event. Eg: Firefox (see https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/relatedTarget)
FWIW, focusin
& focusout
have been supported by Firefox since version 52 and the current one is 67. The latest Firefox ESR still supported is at v60. We can assume focusin
& focusout
to be available in all browsers React should care about IMO, relying on the capture phase of focus
& blur
is not necessary anymore.
@jonathantneal's example curiously does not work as expected for me in Firefox 68, despite Firefox allegedly having support for the events. Can anyone else reproduce?
@eneroth works fine for me on FF 68.0.1, with the caveat that FF does not focus buttons by default when you click them, so I had to tab to it to get the focusin handler to activate for that.
@craigkovatch Alright, thanks. Here's the difference that I'm seeing: http://eneroth.com/gamX3cfz8yBAdiBx4qjxboGm/Firefox%20vs%20Chrome.mov
I.e., the buttons appear when the text field gains focus, then disappear immediately when the text field loses focus. With Chrome, the buttons stay visible.
@eneroth ok I see that too, but I think that is the same thing: buttons not focusing on click in Firefox -- so they wouldn't emit the bubbling focusin event necessary to keep the div displayed. i.e. the text field blurs but the clicked button doesn't focus. If you click into the text field you can tab into the revealed buttons.
More bad news -- it's OS dependent:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#Clicking_and_focus
Easy to fix (as proposed here)
document.addEventListener(
"click",
event => event.target.focus();
);
I want to use onFocusOut to hide an INPUT
that I use to edit the content of a TD
. I need to use an INPUT
because the need to use the type
attribute to select the correct keyboard in an Android Device.
https://caniuse.com/#search=focusout
It seems that all modern navigators implements focusout
Coming back to this thread, I'm not sure what is being asked here. If I understand correctly:
onFocusIn
and onFocusOut
events.onFocus
and onBlur
events, which is analogous to the browser behavior for onFocusIn
and onFocusOut
.I'm not sure that everybody who commented this actually have the same request in mind. If this issue is still relevant to you, can you please restate what you are asking? Taking into account that "add onFocusIn
" doesn't mean much because React onFocus
already behaves like onFocusIn
. Thanks!
I'm not sure that everybody who commented this actually have the same request in mind. If this issue is still relevant to you, can you please restate what you are asking?
I would have to think pretty hard to remember the case that motivated me to subscribe to this and to link it from #13525. I believe I had a case where I thought it would be nice if onFocus
and onBlur
did _not_ bubble, but behaved like the browser events. Then, having onFocusIn
and onFocusOut
would be useful because they do bubble.
@gaearon my request is that React internally listen to focusin
/focusout
rather than focus
/blur
, because there is information missing in the latter (e.g. relatedTarget
, see https://github.com/facebook/react/issues/6410#issuecomment-477858045). But keep the same bubbling behavior as now.
Ahh, yes, @craigkovatch might actually be onto what was causing me trouble.
I believe I had a case where I thought it would be nice if onFocus and onBlur did not bubble, but behaved like the browser events.
This makes sense. The workaround is to check e.target === e.currentTarget
for those cases. Maybe someday we can change this.
my request is that React internally listen to focusin/focusout rather than focus/blur, because there is information missing in the latter
All right, this is good to know. We've actually made that exact change on master so it should go out in 17.
Maybe someday we can change this.
Yeah, that's why I brought it up in https://github.com/facebook/react/issues/13525#issuecomment-465728057 in the context of other breaking changes to align with how DOM events work. From that issue's description around changes to onChange
and onInput
(emphasis mine):
It has been confusing that React uses a different event name for what's known as input event in the DOM. While we generally avoid making big changes like this without significant benefit, in this case we also want to change the behavior to remove some complexity that's only necessary for edge cases like mutating controlled inputs. So it makes sense to do these two changes together, and use that as an opportunity to make onInput and onChange work exactly how the DOM events do for uncontrolled components.
In summary, I don't have a specific need and there are workarounds, but it could be nice to align with the DOM if that means fewer surprises. Of course, there's an argument to be made that the DOM events are surprising or unintuitive, but I'm not here to argue this either way. I'm all set! Glad to know relatedTarget
is coming.
If we are asking for things what I want is focusenter/focusleave like we have for mouse and pointer events. Given that they aren't stanardized tho it's probably not a good fit for react dom
Yeah most of our recent work has been to align closer with the DOM so this is not a good fit at this stage. But there's been parallel work on better accessibility primitives so I think maybe it's in that scope.
In React 17, onFocus
and onBlur
internally listen to focusin
and focusout
.
It seems like this addresses the core of this issue (https://github.com/facebook/react/issues/6410#issuecomment-663731372). It's fair that maybe it would be nice to eventually rename them to align with the browsers (and possibly, add non-bubbling versions). Please feel free to raise new issues for these topics.
To try React 17, install react@next
and react-dom@next
.
Thanks to everyone for the very informative discussion!
I made a small example demonstrating the current behavior based on https://github.com/facebook/react/issues/6410#issuecomment-292895495:
https://codesandbox.io/s/strange-albattani-7tqr7?file=/src/App.js
export default function App() {
return (
<div
tabIndex={1}
onFocus={(e) => {
console.log("focusin (self or child)");
if (e.currentTarget === e.target) {
console.log("focus (self)");
}
if (!e.currentTarget.contains(e.relatedTarget)) {
console.log("focusenter");
}
}}
onBlur={(e) => {
console.log("focusout (self or child)");
if (e.currentTarget === e.target) {
console.log("blur (self)");
}
if (!e.currentTarget.contains(e.relatedTarget)) {
console.log("focusleave");
}
}}
>
<input />
<input />
</div>
);
}
Hopefully this helps as a quick reference when you need to decide on which check to use.
I think there's definitely room for improvement here but if we're talking about API changes, a detailed RFC would be the best way to move this forward: http://github.com/reactjs/rfcs
I'll lock the discussion so people don't lose this canonical answer when coming from Google, but feel free to file new issues if something is unclear or not working.
Most helpful comment
Hey @gaearon @spicyj apparently there is a confusion here, let me explain.
mouseover
andmouseout
bubble up.mouseenter
andmouseleave
don't bubble up. Corresponding React event handlers work the same as native events - awesome.Native
focus
and nativeblur
events don't bubble. Corresponding React event handlersonFocus
andonBlur
do bubble - dun dun dun.Native
focusin
and nativefocusout
events do bubble. React events for these should be implemented and bubble too.Here is a jsfiddle I made to display this. Checked in Chrome only, as since MDN documentation states that this is intended behavior then I believe it should be the same in other browsers.
If I am right about this (please correct me if I am wrong), then the following should be done:
onFocusIn
/onFocusOut
should be removed (obviously).onFocus
should be renamed toonFocusIn
;onBlur
- toonFocusOut
as they currently work the same as nativeonFocusIn
andonFocusOut
work - they bubble.onFocus
andonBlur
event listeners should be implemented in React - which will not bubble.