-
Notifications
You must be signed in to change notification settings - Fork 46.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mouseenter fires on disabled inputs whereas mouseleave does not #4251
Comments
So here is an initial attempt at a fix but I can't figure out how to properly use the below only listens for mouseout/over on the element that has the callback attached :/ var EventConstants = require("./EventConstants");
var EventPropagators = require("./EventPropagators");
var SyntheticMouseEvent = require("./SyntheticMouseEvent");
var containsNode = require("./containsNode");
var ReactMount = require("./ReactMount");
var keyOf = require("./keyOf");
var topLevelTypes = EventConstants.topLevelTypes;
var getFirstReactDOM = ReactMount.getFirstReactDOM;
var eventTypes = {
mouseEnter: {
registrationName: keyOf({ onMouseEnter: null }),
dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver]
},
mouseLeave: {
registrationName: keyOf({ onMouseLeave: null }),
dependencies: [topLevelTypes.topMouseOut, topLevelTypes.topMouseOver]
}
};
var extractedEvents = [null, null];
var EnterLeaveEventPlugin = {
eventTypes: eventTypes,
/**
* For almost every interaction we care about, there will be both a top-level
* `mouseover` and `mouseout` event that occurs. Only use `mouseout` so that
* we do not extract duplicate events. However, moving the mouse into the
* browser from outside will not fire a `mouseout` event. In this case, we use
* the `mouseover` top-level event.
*
* @param {string} topLevelType Record from `EventConstants`.
* @param {DOMEventTarget} topLevelTarget The listening component root node.
* @param {string} topLevelTargetID ID of `topLevelTarget`.
* @param {object} nativeEvent Native browser event.
* @return {*} An accumulation of synthetic events.
* @see {EventPluginHub.extractEvents}
*/
extractEvents: function (topLevelType, topLevelTarget, topLevelTargetID, nativeEvent) {
if (topLevelType !== topLevelTypes.topMouseOut && topLevelType !== topLevelTypes.topMouseOver) {
// Must not be a mouse in or mouse out - ignoring.
return null;
}
var win;
if (topLevelTarget.window === topLevelTarget) {
// `topLevelTarget` is probably a window object.
win = topLevelTarget;
} else {
// TODO: Figure out why `ownerDocument` is sometimes undefined in IE8.
var doc = topLevelTarget.ownerDocument;
if (doc) {
win = doc.defaultView || doc.parentWindow;
} else {
win = window;
}
}
var eventType;
var target = getFirstReactDOM(nativeEvent.target) || win;
var related = getFirstReactDOM(nativeEvent.relatedTarget || nativeEvent.toElement);
//console.log('hii!!')
if (!related || related !== target && !containsNode(target, related)) {
related = related || win;
if (topLevelType === topLevelTypes.topMouseOut) {
eventType = 'mouseLeave';
} else {
eventType = 'mouseEnter';
}
var event = SyntheticMouseEvent.getPooled(eventTypes[eventType], topLevelTargetID, nativeEvent);
event.type = eventType.toLowerCase();
//event.target = target;
event.relatedTarget = related;
// this isn't right!~!!
EventPropagators.accumulateDirectDispatches(event);
return event;
}
return null;
}
};
module.exports = EnterLeaveEventPlugin; |
An example of when you would want Think of a payment button: |
Ping @jimfb @sebmarkbage @syranide Got bit by this again, I'd be happy to PR something, but the current mouseleave/enter code seems really deeply integrated (has its own event propagator?). My current stumbling block is just the below:
The problem is that I need to emit an event that does not fire when the dependent DOM events (out/leave) fire. tests seem using other examples seem either to emit for every child event, or not respond to bubbled child events at all. |
No, I'm not sure. I would be inclined to think that both mouseenter and mouseleave should fire. It's a little weird to me that click doesn't but I can kind of justify that one in my mind. |
@spicyj I tend to agree with you, the problem though is that both mouseout and mouseover do not fire on disabled elements. I am not sure why...all spec stuff I've seen suggests that just click events shouldn't, but browsers seem to go with "all mouse events". In that context it might more consistent to also not allow mouse enter/leave as well. But to be honest its all a moot discussion unless there is an implementation that doesn't rely on either mouseout or mouseover, which may be possible but not common it seems. |
There is also a problem for elements, containing disabled element. <div onMouseEnter={e => console.log("ok")}
onMouseLeave={e => alert("doesn't work")}
>
<button disabled={true} style={{ width: "100%" }}>Test</button>
</div> Native |
A have same issue. I expect to get |
More on this: it works proper in Firefox but doesn't work in Chrome and Safari |
After react 15, onClick on disabled elements does not fire. That makes me a ton of trouble. Should I open an other issue? |
@attilaaronnagy fairly certain it's not a React issue, but a browser one. |
I'm using the latest chrome on the latest mac and with react 0.14.4 this worked perfectly... So I don't think so. Just create an |
@attilaaronnagy I believe this is expected and matches the HTML/DOM spec. @gaearon Did we miss this in the changelog? |
@spicyj and if I need an input, select etc. that is disabled, but has an onClick event what can I do now? (we made a graphical html editor, and I would like to select the components with onClick, but when the edit mode active I would like to disable the component so I can't 'use' it can just 'select' it) |
@spicyj even if I try this:
it's still not working. I don't know what kind of magic you have guys cooked up, but when it's disabled, you are blocking every possible thing no matter whatever I do. I'm thinking about puting a global click event listener on the body and backward calculating which one of the components has been clicked from the coordinates, but that is absurd... Common... |
@attilaaronnagy Browsers don't support click events on inputs. We don't do anything that would affect how addEventListener works. |
@spicyj if the element is not disabled: this code works and the "normal" onClick is also working on an input. I just tried with the same browser in a jsbin, with the older react (0.13) and it's working with the disabled input also. So if the only difference is the react version number... but whatever I gave up. |
@attilaaronnagy This jsbin using React 0.13.3 doesn't work for me: http://react.jsbin.com/qesulefepu/edit?html,js,output Let me know if you're seeing otherwise. |
@spicyj https://jsfiddle.net/qfLzkz5x/ works for me... |
https://jsfiddle.net/qfLzkz5x/ doesn't have a disabled input; if you disable it then you see the behavior I posted. That is the browser's doing, not React's. If you want to capture the onClick event on a disabled input, you have to put a wrapper node around it (or listen to it at the top level, if you prefer). This matches the standard DOM behavior. I personally think this behavior is surprising and not desirable, but we find it valuable to match the DOM spec for this so we're planning to leave it this way. |
Any updates on this onMouseLeave issue? I'm having the same issue with almost identical code to what @andykog posted. https://jsfiddle.net/qfLzkz5x/1/ As a workaround, I've updated my component to watch for the native mouseleave event on the parent of the disabled element, which seems to work, but fires more than expected. My workaround is using code similar to this: https://jsfiddle.net/qfLzkz5x/8/ Edit: Same code with the events bound directly to the disabled button. The native mouseleave event does not work in this case, either. (on Chrome and FF) |
There is also a css workaroud: button[disabled] { pointer-events: none; } Updated @CoryDanielson's fiddle: https://jsfiddle.net/Sl1v3r/sLsut3cy/ |
More experiments http://www.webpackbin.com/VJeejto1Kf |
…d to disabled buttons. facebook/react#4251
Guys, any progress please? Just came over it in real situation when I have text explaining functionality of some actions user can make. However In one case (in compare mode) the download mode of CSV is disabled. Then OnMouseEnter shows the text correctly but the text stays there even user scroll away because the OnMouseLeave doesn't work. Very inconsistent for sure a bug without a doubt. Hoping for quick fix! Thanks.
|
As this seems to be caused by an underlying chrome bug, I'm not sure if a solution is forthcoming. |
Should be fixed in 16.13. If not please create a new issue with a reproducing example. |
To be clear, the change in 16.13 seems to be that |
onMouseOut still works on disabled elements though, so it can be used as an alternative to onMouseLeave |
This is still broken: #19419 opened a new issue for it |
There is an asymmetry to EnterLeave event plugin. Since
mouseenter
is created from the relativeTarget of themouseout
event it fires even though the target is disabled. Since themouseleave
is the inverse, i.e requires that the disabled element fire a mouseout, it doesn't fire amouseleave
for the disabled element.I am pretty sure the correct behavior here is that neither event should fire if its target is disabled, since this mirrors
mouseout
. No idea if none-chrome browsers have the same behavior for which mouse events fire on disabled elements.Additional caveat I just realized, React is probably also not firing
mousenter
events in the case where the mouse leaves a disabled element into a non disabled elementThe text was updated successfully, but these errors were encountered: