Skip to content
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

Figure out what to do with focusin/focusout #88

Closed
smaug---- opened this issue May 22, 2016 · 32 comments · Fixed by #290
Closed

Figure out what to do with focusin/focusout #88

smaug---- opened this issue May 22, 2016 · 32 comments · Fixed by #290

Comments

@smaug----
Copy link

What the spec defines is actually useful behavior, but unfortunately implementations do something totally different. (and that something else happens to be rather useless.) See for example jquery/jquery#3123

@adrianba @RByers @jacobrossi @rniwa would blink/webkit/edge be interested in to fix their implementations, or should we change the spec? (I assume the latter)
There is also the option to remove the events altogether.

@RByers
Copy link

RByers commented May 26, 2016

I don't know much about these events myself, but clearly fixing things to be interoperable one way or another is important. @dtapuska / @choniong thoughts?

@dtapuska
Copy link
Contributor

The ordering of the events focusout & blur, focusin & focus could be made whatever we want as long as they are in pairs. The spec indicates an intermixed scenario which we don't implement.

The relevant code fires blur, focusout, DOMFocusOut and focus, focusin, DOMFocusIn.

We should probably also look at making DOMFocusOut/DOMFocusIn as legacy event mappings for focusin/focusout so that an event target doesn't actually get both.

@smaug----
Copy link
Author

Let's not talk about DOMFocusOut/In here, given that they are by all means deprecated.
But it is the ordering of focusin, focusout, blur and focus which is really odd in some engines. IE seems to have them the right way.

I tried to look for webkit bugs implementing focusin/out, but couldn't find the relevant one. That might have revealed why the behavior is so odd in webkit/blink.

The whole point of focusout/in is that they happen before blur/focus, but apparently that isn't happening, so the use cases for focusout/in are very weak.

@smaug----
Copy link
Author

The ordering of the events focusout & blur, focusin & focus could be made whatever we want as long as they are in pairs.

So that just doesn't make much sense, since, as I said
"The whole point of focusout/in is that they happen before blur/focus, but apparently that isn't happening, so the use cases for focusout/in are very weak."

@dtapuska I assume blink won't be changing its behavior? Same question to @rniwa and @jacobrossi
If so, we need to get whatever odd behavior is implemented spec'ed.

@smaug----
Copy link
Author

@adrianba @rniwa @dtapuska Do you think we should spec the rather useless ordering blink/webkit/edge now has, or would you be willing to fix implementations to follow the spec?
Or third option is to drop support for focusin/out.

@dtapuska
Copy link
Contributor

dtapuska commented Sep 7, 2016

I'm open to fixing blink. I'd like to hear from the edge team before blink would move on this. I think I'd like to see what jquery needs and provide that so they don't need to polyfill it.

@smaug----
Copy link
Author

@mgol ^

@adrianba
Copy link

adrianba commented Sep 7, 2016

Adding @travisleithead.

@RByers
Copy link

RByers commented Sep 8, 2016

If we change blink, with the existing jQuery code continue to work or will it be broken by the change?

@travisleithead
Copy link
Member

I'm definitely in favor of interop, and I'd prefer to have the right (useful) event ordering here that makes the most sense. If we're going to change to a particular new ordering then it: should be done together (all implementations) and done with minimal web compatibility fallout.

I think I'd like to see what jquery needs and provide that so they don't need to polyfill it.

Agree.

If we change blink, with the existing jQuery code continue to work or will it be broken by the change?

Good question.

@smaug----
Copy link
Author

@dtapuska
Copy link
Contributor

@travisleithead do you have any justification why the implementation changed between Edge and IE? I just want to understand if there were any interop concerns in this area.

@smaug----
Copy link
Author

Looks like blink doesn't fire focusin/out on Window object, even though it does fire focus/blur.

@dmethvin
Copy link

We discussed this issue in the jQuery core team meeting today and our recommendation is:

  1. Browsers should use the standards-mandated event order: focusout, focusin, blur, focus. Since focusout and focusin are cancellable they need to happen before focus/blur to prevent take-backsies.

  2. Browsers must provide some feature detect so that developers can know if focusin/out are implemented. Ideally this would be done at the same time as the first point so developers could know that the events are also implemented per-spec. At the moment we don't know of any reliable feature detect for these events.

The only thing jQuery guarantees right now is that focusin happens before focus and focusout happens before blur. Only IE11 has a reliable way to detect the events so jQuery simulates them even when the browser has them, which would be bad except that nobody seems to implement them correctly anyway. Once there is a reliable feature detect jQuery can defer to the working browser implementation.

@smaug----
Copy link
Author

focusin/out are not cancelable in the latest UIEvents spec.

@timmywil
Copy link

Another reason we like the spec order is related to something that's already been mentioned. We've had several tickets over the years about things like .is(':focus') not matching in a focus handler. It would be nice to have a handler for when the element is about to receive focus and one for when it has received focus. The spec handles that well.

@markelog
Copy link

Also see current state of impl in browsers at jquery/jquery#3123 (comment)

@smaug----
Copy link
Author

More weird stuff in blink. If focus is moved in blur handler, focusout it still dispatched, but if
focus is moved in focus handler, focusin isn't dispatched.
So, in blink it is possible to have events for the same target in order: blur, focus, focusin, focusout and yet have that target focused after focusout event.

@smaug----
Copy link
Author

As of now I'm hoping to replicate most of blink's behavior in Gecko, since at least that behavior should be web compatible. But, since that model is quite odd, I'd be very happy if we all agreed to fix this and follow the model closer to what is in the current spec. Unfortunately I haven't seen much related implementation work happening in other browsers, so expectations in that aren't too high.

@dtapuska
Copy link
Contributor

@smaug---- I'd prefer that we actually shipped something that made sense. We have written interop tests here: web-platform-tests/wpt#3857 (from @sunyunjia)

We were waiting on hearing back from jquery. But it appears they were expecting cancelable events for focusin/focusout.

We are going to try to change our processing model this quarter but I'm not sure what monsters are lurking in the corners.

@dmethvin
Copy link

Also, focus-y events should work properly even when the browser window isn't in focus, that would be a good thing to ensure.

@markelog
Copy link

Perhaps you could provide a little bit of context - why it was decided to make focus(in | out) not cancelable?

@dmethvin
Copy link

It does seem like making them cancelable would be handy at times. Note that IE and Edge get focus management wrong when the focus leaves the window and actually prevent the user from even escaping to the browser chrome.

http://jsbin.com/kewuciyide/edit?html,output

@annevk
Copy link
Member

annevk commented Feb 27, 2018

@dtapuska any updates here?

@dtapuska
Copy link
Contributor

We (Chrome) want to do this work although it isn't clear what interop issues we will have so it has gotten low priority. Is there new problems that this would solve which justifies a bump in priority?

@annevk
Copy link
Member

annevk commented Feb 27, 2018

@dtapuska basically, the longer we wait the less likely it becomes. It also would be good to have all focus events defined in detail to make sure that new platform features such as shadow roots interact well with them.

@patricia-gallardo
Copy link

Since my pull-request on uievents/order-of-events/focus-events/focus-manual.html in web-platform-tests is currently blocked because of this issue, I thought I'd chime in :)
web-platform-tests/wpt#9049 (comment)

In my testing for that change and the accompanying change in the w3c html spec:
w3c/html#278

it seems that most browsers have "naturally" converged on pretty much the same behavior which is reflected in my changes in the test. The current test only passes in IE and the behavior is not very intuitive imo. With my changes the test passes in Chrome, Firefox, Safari and almost in Edge. Since this seems to be the model the web has landed on I suggest changing the test rather than the implementers.

@mgol
Copy link

mgol commented Dec 14, 2018

I re-checked browser behavior. Edge 17 & newer now matches Chrome. Firefox implemented that order as well. All dispatch the events in the following order:

  1. blur
  2. focusout
  3. focus
  4. focusin

IE 11 follows the spec order, i.e.:

  1. focusout
  2. focusin
  3. blur
  4. focus

The test case checking native behavior: https://jsfiddle.net/66znLhfw/15/

Is this still realistic to change the order when all current browsers implemented the same non-standard order?

@mfreed7
Copy link

mfreed7 commented Aug 19, 2022

I just hit this issue (again) and I'm curious where we stand. The spec still says:

  1. focusout
  2. focusin
  3. blur
  4. focus

...but Blink, Gecko, and WebKit all do this:

  1. blur
  2. focusout
  3. focus
  4. focusin

While the specified behavior makes much more sense to me, I think that horse has left the barn, and we should likely update the spec to match the behavior. Thoughts?

chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 23, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 23, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 23, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
aarongable pushed a commit to chromium/chromium that referenced this issue Aug 23, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3848846
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1038350}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 23, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3848846
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1038350}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this issue Aug 23, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3848846
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1038350}
@annevk
Copy link
Member

annevk commented Aug 24, 2022

I agree that we should specify what is implemented. And then if there is sufficient interest for a change a new proposal can be made for that and evaluated separately.

Having said that, I suggest that we take this opportunity to define these events in the HTML Standard, where focus is already mostly defined anyway: whatwg/html#3514.

@smaug----
Copy link
Author

I would be very surprised if this can be changed anymore, I mean from what has been shipping for years now.

moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this issue Sep 5, 2022
…'focusin' to 'focus', a=testonly

Automatic update from web-platform-tests
Move the focus-based light dismiss from 'focusin' to 'focus'

The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3848846
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1038350}

--

wpt-commits: 1257a59c8df42427e11956d2265ba822465a938e
wpt-pr: 35569
mjfroman pushed a commit to mjfroman/moz-libwebrtc-third-party that referenced this issue Oct 14, 2022
The problem is described in [1]. While the spec says 'focusin' should
come before 'focus', because that makes sense, implementations actually
do the reverse, including Chromium.  That means that developer event
listeners on 'focus' can show or hide a pop-up, and that gets completed
before the 'focusin' handler gets called. Then, when 'focusin' happens,
the existing logic sees that focus is not in the (now showing) pop-up,
decides that's a light dismiss signal, and hides the pop-up. From the
developer's point of view, the pop-up never opened.

With this new code, light dismiss is handled when the 'focus' event is
fired, and if it isn't cancelled.

[1] w3c/uievents#88

Bug: 1307772
Fixed: 1354293
Change-Id: I20373bcd8aeef24cddac5abd4548e9dc9428abf1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3848846
Reviewed-by: David Baron <dbaron@chromium.org>
Commit-Queue: Mason Freed <masonf@chromium.org>
Auto-Submit: Mason Freed <masonf@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1038350}
NOKEYCHECK=True
GitOrigin-RevId: 57df05daeec7fe3dea09694854601b8b54e667af
@annevk
Copy link
Member

annevk commented May 10, 2023

#185 tracks moving all of this to the HTML Standard, for anyone wondering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment